blob: 4cf9da434ed729754818804752ec57dd01536931 [file] [log] [blame]
#include "host/commands/run_cvd/launch.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <android-base/logging.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/pre_launch_initializers.h"
#include "host/commands/run_cvd/runner_defs.h"
#include "host/libs/vm_manager/crosvm_manager.h"
#include "host/libs/vm_manager/qemu_manager.h"
using cuttlefish::MonitorEntry;
using cuttlefish::RunnerExitCodes;
namespace {
std::string GetAdbConnectorTcpArg(const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
return std::string{"127.0.0.1:"} + std::to_string(instance.host_port());
}
std::string GetAdbConnectorVsockArg(const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
return std::string{"vsock:"} + std::to_string(instance.vsock_guest_cid()) +
std::string{":5555"};
}
bool AdbModeEnabled(const cuttlefish::CuttlefishConfig& config, cuttlefish::AdbMode mode) {
return config.adb_mode().count(mode) > 0;
}
bool AdbVsockTunnelEnabled(const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
return instance.vsock_guest_cid() > 2 &&
AdbModeEnabled(config, cuttlefish::AdbMode::VsockTunnel);
}
bool AdbVsockHalfTunnelEnabled(const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
return instance.vsock_guest_cid() > 2 &&
AdbModeEnabled(config, cuttlefish::AdbMode::VsockHalfTunnel);
}
bool AdbTcpConnectorEnabled(const cuttlefish::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 cuttlefish::CuttlefishConfig& config) {
return config.run_adb_connector() &&
AdbModeEnabled(config, cuttlefish::AdbMode::NativeVsock);
}
cuttlefish::OnSocketReadyCb GetOnSubprocessExitCallback(
const cuttlefish::CuttlefishConfig& config) {
if (config.restart_subprocesses()) {
return cuttlefish::ProcessMonitor::RestartOnExitCb;
} else {
return cuttlefish::ProcessMonitor::DoNotMonitorCb;
}
}
cuttlefish::SharedFD CreateUnixInputServer(const std::string& path) {
auto server =
cuttlefish::SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM, 0666);
if (!server->IsOpen()) {
LOG(ERROR) << "Unable to create unix input server: " << server->StrError();
return cuttlefish::SharedFD();
}
return server;
}
// Creates the frame and input sockets and add the relevant arguments to the vnc
// server and webrtc commands
StreamerLaunchResult CreateStreamerServers(
cuttlefish::Command* cmd, const cuttlefish::CuttlefishConfig& config) {
StreamerLaunchResult server_ret;
cuttlefish::SharedFD touch_server;
cuttlefish::SharedFD keyboard_server;
auto instance = config.ForDefaultInstance();
if (config.vm_manager() == vm_manager::QemuManager::name()) {
cmd->AddParameter("-write_virtio_input");
touch_server = cuttlefish::SharedFD::VsockServer(instance.touch_server_port(),
SOCK_STREAM);
keyboard_server =
cuttlefish::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);
cuttlefish::SharedFD frames_server;
if (config.gpu_mode() == cuttlefish::kGpuModeDrmVirgl ||
config.gpu_mode() == cuttlefish::kGpuModeGfxStream) {
frames_server = CreateUnixInputServer(instance.frames_socket_path());
} else {
frames_server = cuttlefish::SharedFD::VsockServer(instance.frames_server_port(),
SOCK_STREAM);
}
if (!frames_server->IsOpen()) {
LOG(ERROR) << "Could not open frames server: " << frames_server->StrError();
return {};
}
cmd->AddParameter("-frame_server_fd=", frames_server);
return server_ret;
}
} // namespace
std::vector<cuttlefish::SharedFD> LaunchKernelLogMonitor(
const cuttlefish::CuttlefishConfig& config, cuttlefish::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 {};
}
cuttlefish::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 = cuttlefish::SharedFD::Open(log_name.c_str(), O_RDWR);
cuttlefish::Command command(config.kernel_log_monitor_binary());
command.AddParameter("-log_pipe_fd=", pipe);
std::vector<cuttlefish::SharedFD> ret;
if (number_of_event_pipes > 0) {
auto param_builder = command.GetParameterBuilder();
param_builder << "-subscriber_fds=";
for (unsigned int i = 0; i < number_of_event_pipes; ++i) {
cuttlefish::SharedFD event_pipe_write_end, event_pipe_read_end;
if (!cuttlefish::SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end)) {
LOG(ERROR) << "Unable to create boot events pipe: " << strerror(errno);
std::exit(RunnerExitCodes::kPipeIOError);
}
if (i > 0) {
param_builder << ",";
}
param_builder << event_pipe_write_end;
ret.push_back(event_pipe_read_end);
}
param_builder.Build();
}
process_monitor->StartSubprocess(std::move(command),
GetOnSubprocessExitCallback(config));
return ret;
}
void LaunchLogcatReceiver(const cuttlefish::CuttlefishConfig& config,
cuttlefish::ProcessMonitor* process_monitor) {
auto instance = config.ForDefaultInstance();
auto port = instance.logcat_port();
auto socket = cuttlefish::SharedFD::VsockServer(port, SOCK_STREAM);
if (!socket->IsOpen()) {
LOG(ERROR) << "Unable to create logcat server socket: "
<< socket->StrError();
std::exit(RunnerExitCodes::kLogcatServerError);
}
cuttlefish::Command cmd(config.logcat_receiver_binary());
cmd.AddParameter("-server_fd=", socket);
process_monitor->StartSubprocess(std::move(cmd),
GetOnSubprocessExitCallback(config));
return;
}
void LaunchConfigServer(const cuttlefish::CuttlefishConfig& config,
cuttlefish::ProcessMonitor* process_monitor) {
auto instance = config.ForDefaultInstance();
auto port = instance.config_server_port();
auto socket = cuttlefish::SharedFD::VsockServer(port, SOCK_STREAM);
if (!socket->IsOpen()) {
LOG(ERROR) << "Unable to create configuration server socket: "
<< socket->StrError();
std::exit(RunnerExitCodes::kConfigServerError);
}
cuttlefish::Command cmd(config.config_server_binary());
cmd.AddParameter("-server_fd=", socket);
process_monitor->StartSubprocess(std::move(cmd),
GetOnSubprocessExitCallback(config));
return;
}
void LaunchTombstoneReceiverIfEnabled(const cuttlefish::CuttlefishConfig& config,
cuttlefish::ProcessMonitor* process_monitor) {
if (!config.enable_tombstone_receiver()) {
return;
}
auto instance = config.ForDefaultInstance();
std::string tombstoneDir = instance.PerInstancePath("tombstones");
if (!cuttlefish::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 = cuttlefish::SharedFD::VsockServer(port, SOCK_STREAM);
if (!socket->IsOpen()) {
LOG(ERROR) << "Unable to create tombstone server socket: "
<< socket->StrError();
std::exit(RunnerExitCodes::kTombstoneServerError);
return;
}
cuttlefish::Command cmd(config.tombstone_receiver_binary());
cmd.AddParameter("-server_fd=", socket);
cmd.AddParameter("-tombstone_dir=", tombstoneDir);
process_monitor->StartSubprocess(std::move(cmd),
GetOnSubprocessExitCallback(config));
return;
}
StreamerLaunchResult LaunchVNCServer(
const cuttlefish::CuttlefishConfig& config, cuttlefish::ProcessMonitor* process_monitor,
std::function<bool(MonitorEntry*)> callback) {
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());
cuttlefish::Command vnc_server(config.vnc_server_binary());
vnc_server.AddParameter(port_options);
auto server_ret = CreateStreamerServers(&vnc_server, config);
process_monitor->StartSubprocess(std::move(vnc_server), callback);
server_ret.launched = true;
return server_ret;
}
void LaunchAdbConnectorIfEnabled(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config,
cuttlefish::SharedFD adbd_events_pipe) {
cuttlefish::Command adb_connector(config.adb_connector_binary());
adb_connector.AddParameter("-adbd_events_fd=", adbd_events_pipe);
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->StartSubprocess(std::move(adb_connector),
GetOnSubprocessExitCallback(config));
}
}
StreamerLaunchResult LaunchWebRTC(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
if (config.ForDefaultInstance().start_webrtc_sig_server()) {
cuttlefish::Command sig_server(config.sig_server_binary());
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->StartSubprocess(std::move(sig_server),
GetOnSubprocessExitCallback(config));
}
// 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::Command webrtc(config.webrtc_binary());
webrtc.AddParameter("-public_ip=", config.webrtc_public_ip());
auto server_ret = CreateStreamerServers(&webrtc, config);
if (config.webrtc_enable_adb_websocket()) {
auto instance = config.ForDefaultInstance();
webrtc.AddParameter("--adb=", instance.adb_ip_and_port());
}
// TODO get from launcher params
process_monitor->StartSubprocess(std::move(webrtc),
GetOnSubprocessExitCallback(config));
server_ret.launched = true;
return server_ret;
}
void LaunchSocketVsockProxyIfEnabled(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
if (AdbVsockTunnelEnabled(config)) {
cuttlefish::Command adb_tunnel(config.socket_vsock_proxy_binary());
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->StartSubprocess(std::move(adb_tunnel),
GetOnSubprocessExitCallback(config));
}
if (AdbVsockHalfTunnelEnabled(config)) {
cuttlefish::Command adb_tunnel(config.socket_vsock_proxy_binary());
adb_tunnel.AddParameter("--server=tcp");
adb_tunnel.AddParameter("--vsock_port=5555");
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->StartSubprocess(std::move(adb_tunnel),
GetOnSubprocessExitCallback(config));
}
}
void LaunchTpmSimulator(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
auto instance = config.ForDefaultInstance();
auto port = instance.tpm_port();
auto socket = cuttlefish::SharedFD::VsockServer(port, SOCK_STREAM);
cuttlefish::Command tpm_command(
cuttlefish::DefaultHostArtifactsPath("bin/tpm_simulator_manager"));
tpm_command.AddParameter("-port=", port);
process_monitor->StartSubprocess(std::move(tpm_command),
GetOnSubprocessExitCallback(config));
cuttlefish::Command proxy_command(config.socket_vsock_proxy_binary());
proxy_command.AddParameter("--server=vsock");
proxy_command.AddParameter("--tcp_port=", port);
proxy_command.AddParameter("--vsock_port=", port);
process_monitor->StartSubprocess(std::move(proxy_command),
GetOnSubprocessExitCallback(config));
}
void LaunchMetrics(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
cuttlefish::Command metrics(config.metrics_binary());
process_monitor->StartSubprocess(std::move(metrics),
GetOnSubprocessExitCallback(config));
}
void LaunchTpmPassthrough(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
auto server = cuttlefish::SharedFD::VsockServer(SOCK_STREAM);
if (!server->IsOpen()) {
LOG(ERROR) << "Unable to create tpm passthrough server: "
<< server->StrError();
std::exit(RunnerExitCodes::kTpmPassthroughError);
}
cuttlefish::Command tpm_command(
cuttlefish::DefaultHostArtifactsPath("bin/vtpm_passthrough"));
tpm_command.AddParameter("-server_fd=", server);
tpm_command.AddParameter("-device=", config.tpm_device());
process_monitor->StartSubprocess(std::move(tpm_command),
GetOnSubprocessExitCallback(config));
}
void LaunchTpm(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
if (config.tpm_device() != "") {
if (config.tpm_binary() != "") {
LOG(WARNING)
<< "Both -tpm_device and -tpm_binary were set. Using -tpm_device.";
}
LaunchTpmPassthrough(process_monitor, config);
} else if (config.tpm_binary() != "") {
LaunchTpmSimulator(process_monitor, config);
}
}
void LaunchSecureEnvironment(cuttlefish::ProcessMonitor* process_monitor,
const cuttlefish::CuttlefishConfig& config) {
auto port = config.ForDefaultInstance().keymaster_vsock_port();
auto server = cuttlefish::SharedFD::VsockServer(port, SOCK_STREAM);
cuttlefish::Command command(cuttlefish::DefaultHostArtifactsPath("bin/secure_env"));
command.AddParameter("-keymaster_fd=", server);
process_monitor->StartSubprocess(std::move(command),
GetOnSubprocessExitCallback(config));
}