| #include "host/commands/run_cvd/launch.h" |
| |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <android-base/logging.h> |
| #include <android-base/strings.h> |
| |
| #include "common/libs/fs/shared_buf.h" |
| #include "common/libs/fs/shared_fd.h" |
| #include "common/libs/utils/files.h" |
| #include "common/libs/utils/size_utils.h" |
| #include "host/commands/run_cvd/runner_defs.h" |
| #include "host/libs/config/known_paths.h" |
| #include "host/libs/vm_manager/crosvm_manager.h" |
| #include "host/libs/vm_manager/qemu_manager.h" |
| |
| namespace cuttlefish { |
| |
| using vm_manager::QemuManager; |
| |
| namespace { |
| |
| std::string GetAdbConnectorTcpArg(const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| return std::string{"0.0.0.0:"} + std::to_string(instance.host_port()); |
| } |
| |
| std::string GetAdbConnectorVsockArg(const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| return std::string{"vsock:"} + std::to_string(instance.vsock_guest_cid()) + |
| std::string{":5555"}; |
| } |
| |
| bool AdbModeEnabled(const CuttlefishConfig& config, AdbMode mode) { |
| return config.adb_mode().count(mode) > 0; |
| } |
| |
| bool AdbVsockTunnelEnabled(const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| return instance.vsock_guest_cid() > 2 && |
| AdbModeEnabled(config, AdbMode::VsockTunnel); |
| } |
| |
| bool AdbVsockHalfTunnelEnabled(const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| return instance.vsock_guest_cid() > 2 && |
| AdbModeEnabled(config, AdbMode::VsockHalfTunnel); |
| } |
| |
| bool AdbTcpConnectorEnabled(const CuttlefishConfig& config) { |
| bool vsock_tunnel = AdbVsockTunnelEnabled(config); |
| bool vsock_half_tunnel = AdbVsockHalfTunnelEnabled(config); |
| return config.run_adb_connector() && (vsock_tunnel || vsock_half_tunnel); |
| } |
| |
| bool AdbVsockConnectorEnabled(const CuttlefishConfig& config) { |
| return config.run_adb_connector() && |
| AdbModeEnabled(config, AdbMode::NativeVsock); |
| } |
| |
| SharedFD CreateUnixInputServer(const std::string& path) { |
| auto server = |
| SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666); |
| if (!server->IsOpen()) { |
| LOG(ERROR) << "Unable to create unix input server: " << server->StrError(); |
| return {}; |
| } |
| return server; |
| } |
| |
| // Creates the frame and input sockets and add the relevant arguments to the vnc |
| // server and webrtc commands |
| void CreateStreamerServers(Command* cmd, const CuttlefishConfig& config) { |
| SharedFD touch_server; |
| SharedFD keyboard_server; |
| |
| auto instance = config.ForDefaultInstance(); |
| if (config.vm_manager() == QemuManager::name()) { |
| cmd->AddParameter("-write_virtio_input"); |
| |
| touch_server = SharedFD::VsockServer(instance.touch_server_port(), |
| SOCK_STREAM); |
| keyboard_server = SharedFD::VsockServer(instance.keyboard_server_port(), |
| SOCK_STREAM); |
| } else { |
| touch_server = CreateUnixInputServer(instance.touch_socket_path()); |
| keyboard_server = CreateUnixInputServer(instance.keyboard_socket_path()); |
| } |
| if (!touch_server->IsOpen()) { |
| LOG(ERROR) << "Could not open touch server: " << touch_server->StrError(); |
| return; |
| } |
| cmd->AddParameter("-touch_fd=", touch_server); |
| |
| if (!keyboard_server->IsOpen()) { |
| LOG(ERROR) << "Could not open keyboard server: " |
| << keyboard_server->StrError(); |
| return; |
| } |
| cmd->AddParameter("-keyboard_fd=", keyboard_server); |
| |
| if (config.enable_webrtc() && |
| config.vm_manager() == vm_manager::CrosvmManager::name()) { |
| SharedFD switches_server = |
| CreateUnixInputServer(instance.switches_socket_path()); |
| if (!switches_server->IsOpen()) { |
| LOG(ERROR) << "Could not open switches server: " |
| << switches_server->StrError(); |
| return; |
| } |
| cmd->AddParameter("-switches_fd=", switches_server); |
| } |
| |
| SharedFD frames_server = CreateUnixInputServer(instance.frames_socket_path()); |
| if (!frames_server->IsOpen()) { |
| LOG(ERROR) << "Could not open frames server: " << frames_server->StrError(); |
| return; |
| } |
| cmd->AddParameter("-frame_server_fd=", frames_server); |
| |
| if (config.enable_audio()) { |
| auto path = config.ForDefaultInstance().audio_server_path(); |
| auto audio_server = |
| SharedFD::SocketLocalServer(path.c_str(), false, SOCK_SEQPACKET, 0666); |
| if (!audio_server->IsOpen()) { |
| LOG(ERROR) << "Could not create audio server: " << audio_server->StrError(); |
| return; |
| } |
| cmd->AddParameter("--audio_server_fd=", audio_server); |
| } |
| } |
| |
| } // namespace |
| |
| std::vector<SharedFD> LaunchKernelLogMonitor( |
| const CuttlefishConfig& config, ProcessMonitor* process_monitor, |
| unsigned int number_of_event_pipes) { |
| auto instance = config.ForDefaultInstance(); |
| auto log_name = instance.kernel_log_pipe_name(); |
| if (mkfifo(log_name.c_str(), 0600) != 0) { |
| LOG(ERROR) << "Unable to create named pipe at " << log_name << ": " |
| << strerror(errno); |
| return {}; |
| } |
| |
| SharedFD pipe; |
| // 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. |
| pipe = SharedFD::Open(log_name.c_str(), O_RDWR); |
| Command command(KernelLogMonitorBinary()); |
| command.AddParameter("-log_pipe_fd=", pipe); |
| |
| std::vector<SharedFD> ret; |
| |
| if (number_of_event_pipes > 0) { |
| command.AddParameter("-subscriber_fds="); |
| for (unsigned int i = 0; i < number_of_event_pipes; ++i) { |
| SharedFD event_pipe_write_end, event_pipe_read_end; |
| if (!SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end)) { |
| LOG(ERROR) << "Unable to create kernel log events pipe: " << strerror(errno); |
| std::exit(RunnerExitCodes::kPipeIOError); |
| } |
| if (i > 0) { |
| command.AppendToLastParameter(","); |
| } |
| command.AppendToLastParameter(event_pipe_write_end); |
| ret.push_back(event_pipe_read_end); |
| } |
| } |
| |
| process_monitor->AddCommand(std::move(command)); |
| |
| return ret; |
| } |
| |
| void LaunchRootCanal(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| if (!config.enable_host_bluetooth()) { |
| return; |
| } |
| |
| auto instance = config.ForDefaultInstance(); |
| Command command(RootCanalBinary()); |
| |
| // Test port |
| command.AddParameter(instance.rootcanal_test_port()); |
| // HCI server port |
| command.AddParameter(instance.rootcanal_hci_port()); |
| // Link server port |
| command.AddParameter(instance.rootcanal_link_port()); |
| // Bluetooth controller properties file |
| command.AddParameter("--controller_properties_file=", |
| instance.rootcanal_config_file()); |
| // Default commands file |
| command.AddParameter("--default_commands_file=", |
| instance.rootcanal_default_commands_file()); |
| |
| process_monitor->AddCommand(std::move(command)); |
| return; |
| } |
| |
| void LaunchLogcatReceiver(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| auto instance = config.ForDefaultInstance(); |
| auto log_name = instance.logcat_pipe_name(); |
| if (mkfifo(log_name.c_str(), 0600) != 0) { |
| LOG(ERROR) << "Unable to create named pipe at " << log_name << ": " |
| << strerror(errno); |
| return; |
| } |
| |
| SharedFD pipe; |
| // 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); |
| Command command(LogcatReceiverBinary()); |
| command.AddParameter("-log_pipe_fd=", pipe); |
| |
| process_monitor->AddCommand(std::move(command)); |
| return; |
| } |
| |
| void LaunchConfigServer(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| auto instance = config.ForDefaultInstance(); |
| auto port = instance.config_server_port(); |
| auto socket = SharedFD::VsockServer(port, SOCK_STREAM); |
| if (!socket->IsOpen()) { |
| LOG(ERROR) << "Unable to create configuration server socket: " |
| << socket->StrError(); |
| std::exit(RunnerExitCodes::kConfigServerError); |
| } |
| Command cmd(ConfigServerBinary()); |
| cmd.AddParameter("-server_fd=", socket); |
| process_monitor->AddCommand(std::move(cmd)); |
| return; |
| } |
| |
| void LaunchTombstoneReceiver(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| auto instance = config.ForDefaultInstance(); |
| |
| std::string tombstoneDir = instance.PerInstancePath("tombstones"); |
| if (!DirectoryExists(tombstoneDir.c_str())) { |
| LOG(DEBUG) << "Setting up " << tombstoneDir; |
| if (mkdir(tombstoneDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < |
| 0) { |
| LOG(ERROR) << "Failed to create tombstone directory: " << tombstoneDir |
| << ". Error: " << errno; |
| exit(RunnerExitCodes::kTombstoneDirCreationError); |
| return; |
| } |
| } |
| |
| auto port = instance.tombstone_receiver_port(); |
| auto socket = SharedFD::VsockServer(port, SOCK_STREAM); |
| if (!socket->IsOpen()) { |
| LOG(ERROR) << "Unable to create tombstone server socket: " |
| << socket->StrError(); |
| std::exit(RunnerExitCodes::kTombstoneServerError); |
| return; |
| } |
| Command cmd(TombstoneReceiverBinary()); |
| cmd.AddParameter("-server_fd=", socket); |
| cmd.AddParameter("-tombstone_dir=", tombstoneDir); |
| |
| process_monitor->AddCommand(std::move(cmd)); |
| return; |
| } |
| |
| void LaunchVNCServer(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| auto instance = config.ForDefaultInstance(); |
| // Launch the vnc server, don't wait for it to complete |
| auto port_options = "-port=" + std::to_string(instance.vnc_server_port()); |
| Command vnc_server(VncServerBinary()); |
| vnc_server.AddParameter(port_options); |
| |
| CreateStreamerServers(&vnc_server, config); |
| |
| process_monitor->AddCommand(std::move(vnc_server)); |
| } |
| |
| void LaunchAdbConnectorIfEnabled(ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config) { |
| Command adb_connector(AdbConnectorBinary()); |
| std::set<std::string> addresses; |
| |
| if (AdbTcpConnectorEnabled(config)) { |
| addresses.insert(GetAdbConnectorTcpArg(config)); |
| } |
| if (AdbVsockConnectorEnabled(config)) { |
| addresses.insert(GetAdbConnectorVsockArg(config)); |
| } |
| |
| if (addresses.size() > 0) { |
| std::string address_arg = "--addresses="; |
| for (auto& arg : addresses) { |
| address_arg += arg + ","; |
| } |
| address_arg.pop_back(); |
| adb_connector.AddParameter(address_arg); |
| process_monitor->AddCommand(std::move(adb_connector)); |
| } |
| } |
| |
| void LaunchWebRTC(ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config, |
| SharedFD kernel_log_events_pipe) { |
| if (config.ForDefaultInstance().start_webrtc_sig_server()) { |
| Command sig_server(WebRtcSigServerBinary()); |
| sig_server.AddParameter("-assets_dir=", config.webrtc_assets_dir()); |
| if (!config.webrtc_certs_dir().empty()) { |
| sig_server.AddParameter("-certs_dir=", config.webrtc_certs_dir()); |
| } |
| sig_server.AddParameter("-http_server_port=", config.sig_server_port()); |
| process_monitor->AddCommand(std::move(sig_server)); |
| } |
| |
| // Currently there is no way to ensure the signaling server will already have |
| // bound the socket to the port by the time the webrtc process runs (the |
| // common technique of doing it from the launcher is not possible here as the |
| // server library being used creates its own sockets). However, this issue is |
| // mitigated slightly by doing some retrying and backoff in the webrtc process |
| // when connecting to the websocket, so it shouldn't be an issue most of the |
| // time. |
| cuttlefish::SharedFD client_socket; |
| cuttlefish::SharedFD host_socket; |
| CHECK(cuttlefish::SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, |
| &client_socket, &host_socket)) |
| << "Could not open command socket for webRTC"; |
| |
| auto stopper = [host_socket = std::move(host_socket)](cuttlefish::Subprocess* proc) { |
| struct timeval timeout; |
| timeout.tv_sec = 3; |
| timeout.tv_usec = 0; |
| CHECK(host_socket->SetSockOpt(SOL_SOCKET, SO_RCVTIMEO, &timeout, |
| sizeof(timeout)) == 0) |
| << "Could not set receive timeout"; |
| |
| cuttlefish::WriteAll(host_socket, "C"); |
| char response[1]; |
| int read_ret = host_socket->Read(response, sizeof(response)); |
| if (read_ret != 0) { |
| LOG(ERROR) << "Failed to read response from webrtc"; |
| } |
| cuttlefish::KillSubprocess(proc); |
| return true; |
| }; |
| |
| cuttlefish::Command webrtc(cuttlefish::WebRtcBinary(), |
| cuttlefish::SubprocessStopper(stopper)); |
| |
| webrtc.UnsetFromEnvironment({"http_proxy"}); |
| |
| CreateStreamerServers(&webrtc, config); |
| |
| webrtc.AddParameter("--command_fd=", client_socket); |
| |
| webrtc.AddParameter("-kernel_log_events_fd=", kernel_log_events_pipe); |
| |
| LaunchCustomActionServers(webrtc, process_monitor, config); |
| |
| // TODO get from launcher params |
| process_monitor->AddCommand(std::move(webrtc)); |
| } |
| |
| bool StopModemSimulator() { |
| auto config = CuttlefishConfig::Get(); |
| auto instance = config->ForDefaultInstance(); |
| |
| std::string monitor_socket_name = "modem_simulator"; |
| std::stringstream ss; |
| ss << instance.host_port(); |
| monitor_socket_name.append(ss.str()); |
| auto monitor_sock = SharedFD::SocketLocalClient( |
| monitor_socket_name.c_str(), true, SOCK_STREAM); |
| if (!monitor_sock->IsOpen()) { |
| LOG(ERROR) << "The connection to modem simulator is closed"; |
| return false; |
| } |
| std::string msg("STOP"); |
| if (monitor_sock->Write(msg.data(), msg.size()) < 0) { |
| monitor_sock->Close(); |
| LOG(ERROR) << "Failed to send 'STOP' to modem simulator"; |
| return false; |
| } |
| char buf[64] = {0}; |
| if (monitor_sock->Read(buf, sizeof(buf)) <= 0) { |
| monitor_sock->Close(); |
| LOG(ERROR) << "Failed to read message from modem simulator"; |
| return false; |
| } |
| if (strcmp(buf, "OK")) { |
| monitor_sock->Close(); |
| LOG(ERROR) << "Read '" << buf << "' instead of 'OK' from modem simulator"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void LaunchModemSimulatorIfEnabled( |
| const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| if (!config.enable_modem_simulator()) { |
| LOG(DEBUG) << "Modem simulator not enabled"; |
| return; |
| } |
| |
| int instance_number = config.modem_simulator_instance_number(); |
| if (instance_number > 3 /* max value */ || instance_number < 0) { |
| LOG(ERROR) |
| << "Modem simulator instance number should range between 1 and 3"; |
| return; |
| } |
| |
| Command cmd( |
| ModemSimulatorBinary(), [](Subprocess* proc) { |
| auto stopped = StopModemSimulator(); |
| if (stopped) { |
| return true; |
| } |
| LOG(WARNING) << "Failed to stop modem simulator nicely, " |
| << "attempting to KILL"; |
| return KillSubprocess(proc); |
| }); |
| |
| auto sim_type = config.modem_simulator_sim_type(); |
| cmd.AddParameter(std::string{"-sim_type="} + std::to_string(sim_type)); |
| |
| auto instance = config.ForDefaultInstance(); |
| auto ports = instance.modem_simulator_ports(); |
| cmd.AddParameter("-server_fds="); |
| for (int i = 0; i < instance_number; ++i) { |
| auto pos = ports.find(','); |
| auto temp = (pos != std::string::npos) ? ports.substr(0, pos - 1) : ports; |
| auto port = std::stoi(temp); |
| ports = ports.substr(pos + 1); |
| |
| auto socket = SharedFD::VsockServer(port, SOCK_STREAM); |
| if (!socket->IsOpen()) { |
| LOG(ERROR) << "Unable to create modem simulator server socket: " |
| << socket->StrError(); |
| std::exit(RunnerExitCodes::kModemSimulatorServerError); |
| } |
| if (i > 0) { |
| cmd.AppendToLastParameter(","); |
| } |
| cmd.AppendToLastParameter(socket); |
| } |
| |
| process_monitor->AddCommand(std::move(cmd)); |
| } |
| |
| void LaunchSocketVsockProxyIfEnabled(ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config, |
| SharedFD adbd_events_pipe) { |
| auto instance = config.ForDefaultInstance(); |
| auto append = [](const std::string& s, const int i) -> std::string { |
| return s + std::to_string(i); |
| }; |
| if (AdbVsockTunnelEnabled(config)) { |
| Command adb_tunnel(SocketVsockProxyBinary()); |
| adb_tunnel.AddParameter("-adbd_events_fd=", adbd_events_pipe); |
| /** |
| * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host. It assumes that |
| * another sv proxy runs inside the guest. see: shared/config/init.vendor.rc |
| * The sv proxy in the guest exposes vsock:cid:6520 across the cuttlefish instances |
| * in multi-tenancy. cid is different per instance. |
| * |
| * This host sv proxy should cooperate with the guest sv proxy. Thus, one end of |
| * the tunnel is vsock:cid:6520 regardless of instance number. Another end faces |
| * the host adb daemon via tcp. Thus, the server type is tcp here. The tcp port |
| * differs from instance to instance, and is instance.host_port() |
| * |
| */ |
| adb_tunnel.AddParameter("--server=tcp"); |
| adb_tunnel.AddParameter("--vsock_port=6520"); |
| adb_tunnel.AddParameter(std::string{"--tcp_port="} + |
| std::to_string(instance.host_port())); |
| adb_tunnel.AddParameter(std::string{"--vsock_cid="} + |
| std::to_string(instance.vsock_guest_cid())); |
| process_monitor->AddCommand(std::move(adb_tunnel)); |
| } |
| if (AdbVsockHalfTunnelEnabled(config)) { |
| Command adb_tunnel(SocketVsockProxyBinary()); |
| adb_tunnel.AddParameter("-adbd_events_fd=", adbd_events_pipe); |
| /* |
| * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host, and cooperates with |
| * the adbd inside the guest. See this file: |
| * shared/device.mk, especially the line says "persist.adb.tcp.port=" |
| * |
| * The guest adbd is listening on vsock:cid:5555 across cuttlefish instances. |
| * Sv proxy faces the host adb daemon via tcp. The server type should be therefore |
| * tcp, and the port should differ from instance to instance and be equal to |
| * instance.host_port() |
| */ |
| adb_tunnel.AddParameter("--server=tcp"); |
| adb_tunnel.AddParameter(append("--vsock_port=", 5555)); |
| adb_tunnel.AddParameter(append("--tcp_port=", instance.host_port())); |
| adb_tunnel.AddParameter(append("--vsock_cid=", instance.vsock_guest_cid())); |
| process_monitor->AddCommand(std::move(adb_tunnel)); |
| } |
| } |
| |
| void LaunchMetrics(ProcessMonitor* process_monitor) { |
| Command metrics(MetricsBinary()); |
| |
| process_monitor->AddCommand(std::move(metrics)); |
| } |
| |
| void LaunchGnssGrpcProxyServerIfEnabled(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| if (!config.enable_gnss_grpc_proxy() || |
| !FileExists(GnssGrpcProxyBinary())) { |
| return; |
| } |
| |
| Command gnss_grpc_proxy_cmd(GnssGrpcProxyBinary()); |
| auto instance = config.ForDefaultInstance(); |
| |
| auto gnss_in_pipe_name = instance.gnss_in_pipe_name(); |
| if (mkfifo(gnss_in_pipe_name.c_str(), 0600) != 0) { |
| auto error = errno; |
| LOG(ERROR) << "Failed to create gnss input fifo for crosvm: " |
| << strerror(error); |
| return; |
| } |
| |
| auto gnss_out_pipe_name = instance.gnss_out_pipe_name(); |
| if (mkfifo(gnss_out_pipe_name.c_str(), 0660) != 0) { |
| auto error = errno; |
| LOG(ERROR) << "Failed to create gnss output fifo for crosvm: " |
| << strerror(error); |
| return; |
| } |
| |
| // 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 |
| SharedFD gnss_grpc_proxy_in_wr = |
| SharedFD::Open(gnss_in_pipe_name.c_str(), O_RDWR); |
| if (!gnss_grpc_proxy_in_wr->IsOpen()) { |
| LOG(ERROR) << "Failed to open gnss_grpc_proxy input fifo for writes: " |
| << gnss_grpc_proxy_in_wr->StrError(); |
| return; |
| } |
| |
| SharedFD gnss_grpc_proxy_out_rd = |
| SharedFD::Open(gnss_out_pipe_name.c_str(), O_RDWR); |
| if (!gnss_grpc_proxy_out_rd->IsOpen()) { |
| LOG(ERROR) << "Failed to open gnss_grpc_proxy output fifo for reads: " |
| << gnss_grpc_proxy_out_rd->StrError(); |
| return; |
| } |
| |
| 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()); |
| } |
| process_monitor->AddCommand(std::move(gnss_grpc_proxy_cmd)); |
| } |
| |
| void LaunchBluetoothConnector(ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| std::vector<std::string> fifo_paths = { |
| instance.PerInstanceInternalPath("bt_fifo_vm.in"), |
| instance.PerInstanceInternalPath("bt_fifo_vm.out"), |
| }; |
| std::vector<SharedFD> fifos; |
| for (const auto& path : fifo_paths) { |
| unlink(path.c_str()); |
| if (mkfifo(path.c_str(), 0660) < 0) { |
| PLOG(ERROR) << "Could not create " << path; |
| return; |
| } |
| auto fd = SharedFD::Open(path, O_RDWR); |
| if (!fd->IsOpen()) { |
| LOG(ERROR) << "Could not open " << path << ": " << fd->StrError(); |
| return; |
| } |
| fifos.push_back(fd); |
| } |
| |
| Command command(DefaultHostArtifactsPath("bin/bt_connector")); |
| command.AddParameter("-bt_out=", fifos[0]); |
| command.AddParameter("-bt_in=", fifos[1]); |
| command.AddParameter("-hci_port=", instance.rootcanal_hci_port()); |
| command.AddParameter("-link_port=", instance.rootcanal_link_port()); |
| command.AddParameter("-test_port=", instance.rootcanal_test_port()); |
| process_monitor->AddCommand(std::move(command)); |
| } |
| |
| void LaunchSecureEnvironment(ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config) { |
| auto instance = config.ForDefaultInstance(); |
| 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()); |
| if (mkfifo(path.c_str(), 0600) < 0) { |
| PLOG(ERROR) << "Could not create " << path; |
| return; |
| } |
| auto fd = SharedFD::Open(path, O_RDWR); |
| if (!fd->IsOpen()) { |
| LOG(ERROR) << "Could not open " << path << ": " << fd->StrError(); |
| return; |
| } |
| fifos.push_back(fd); |
| } |
| |
| Command command(HostBinaryPath("secure_env")); |
| 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); |
| |
| process_monitor->AddCommand(std::move(command)); |
| } |
| |
| void LaunchCustomActionServers(Command& webrtc_cmd, |
| ProcessMonitor* process_monitor, |
| const CuttlefishConfig& config) { |
| bool first = true; |
| for (const auto& custom_action : config.custom_actions()) { |
| if (custom_action.server) { |
| // Create a socket pair that will be used for communication between |
| // WebRTC and the action server. |
| SharedFD webrtc_socket, action_server_socket; |
| if (!SharedFD::SocketPair(AF_LOCAL, SOCK_STREAM, 0, |
| &webrtc_socket, &action_server_socket)) { |
| LOG(ERROR) << "Unable to create custom action server socket pair: " |
| << strerror(errno); |
| continue; |
| } |
| |
| // Launch the action server, providing its socket pair fd as the only argument. |
| std::string binary = "bin/" + *(custom_action.server); |
| Command command(DefaultHostArtifactsPath(binary)); |
| command.AddParameter(action_server_socket); |
| process_monitor->AddCommand(std::move(command)); |
| |
| // Pass the WebRTC socket pair fd to WebRTC. |
| if (first) { |
| first = false; |
| webrtc_cmd.AddParameter("-action_servers=", *custom_action.server, ":", webrtc_socket); |
| } else { |
| webrtc_cmd.AppendToLastParameter(",", *custom_action.server, ":", webrtc_socket); |
| } |
| } |
| } |
| } |
| |
| void LaunchVehicleHalServerIfEnabled(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) { |
| if (!config.enable_vehicle_hal_grpc_server() || |
| !FileExists(config.vehicle_hal_grpc_server_binary())) { |
| return; |
| } |
| |
| Command grpc_server(config.vehicle_hal_grpc_server_binary()); |
| auto instance = config.ForDefaultInstance(); |
| |
| 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); |
| process_monitor->AddCommand(std::move(grpc_server)); |
| } |
| |
| void LaunchConsoleForwarderIfEnabled(const CuttlefishConfig& config, |
| ProcessMonitor* process_monitor) |
| { |
| if (!config.console()) { |
| return; |
| } |
| |
| Command console_forwarder_cmd(ConsoleForwarderBinary()); |
| auto instance = config.ForDefaultInstance(); |
| |
| auto console_in_pipe_name = instance.console_in_pipe_name(); |
| if (mkfifo(console_in_pipe_name.c_str(), 0600) != 0) { |
| auto error = errno; |
| LOG(ERROR) << "Failed to create console input fifo for crosvm: " |
| << strerror(error); |
| return; |
| } |
| |
| auto console_out_pipe_name = instance.console_out_pipe_name(); |
| if (mkfifo(console_out_pipe_name.c_str(), 0660) != 0) { |
| auto error = errno; |
| LOG(ERROR) << "Failed to create console output fifo for crosvm: " |
| << strerror(error); |
| return; |
| } |
| |
| // 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 |
| SharedFD console_forwarder_in_wr = |
| SharedFD::Open(console_in_pipe_name.c_str(), O_RDWR); |
| if (!console_forwarder_in_wr->IsOpen()) { |
| LOG(ERROR) << "Failed to open console_forwarder input fifo for writes: " |
| << console_forwarder_in_wr->StrError(); |
| return; |
| } |
| |
| SharedFD console_forwarder_out_rd = |
| SharedFD::Open(console_out_pipe_name.c_str(), O_RDWR); |
| if (!console_forwarder_out_rd->IsOpen()) { |
| LOG(ERROR) << "Failed to open console_forwarder output fifo for reads: " |
| << console_forwarder_out_rd->StrError(); |
| return; |
| } |
| |
| console_forwarder_cmd.AddParameter("--console_in_fd=", console_forwarder_in_wr); |
| console_forwarder_cmd.AddParameter("--console_out_fd=", console_forwarder_out_rd); |
| process_monitor->AddCommand(std::move(console_forwarder_cmd)); |
| } |
| |
| } // namespace cuttlefish |