You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
13 KiB
374 lines
13 KiB
//
|
|
// 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 <utility>
|
|
|
|
#include "common/libs/fs/shared_fd.h"
|
|
#include "common/libs/utils/files.h"
|
|
#include "common/libs/utils/subprocess.h"
|
|
#include "host/commands/run_cvd/process_monitor.h"
|
|
#include "host/commands/run_cvd/runner_defs.h"
|
|
#include "host/libs/config/cuttlefish_config.h"
|
|
#include "host/libs/config/known_paths.h"
|
|
|
|
namespace cuttlefish {
|
|
|
|
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
|
|
|
|
KernelLogMonitorData LaunchKernelLogMonitor(
|
|
const CuttlefishConfig& config, 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);
|
|
|
|
KernelLogMonitorData 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.pipes.push_back(event_pipe_read_end);
|
|
}
|
|
}
|
|
|
|
ret.commands.emplace_back(std::move(command));
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::vector<Command> LaunchRootCanal(const CuttlefishConfig& config) {
|
|
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());
|
|
|
|
return single_element_emplace(std::move(command));
|
|
}
|
|
|
|
std::vector<Command> LaunchLogcatReceiver(const CuttlefishConfig& config) {
|
|
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);
|
|
|
|
return single_element_emplace(std::move(command));
|
|
}
|
|
|
|
std::vector<Command> LaunchConfigServer(const CuttlefishConfig& config) {
|
|
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);
|
|
return single_element_emplace(std::move(cmd));
|
|
}
|
|
|
|
std::vector<Command> LaunchTombstoneReceiver(const CuttlefishConfig& config) {
|
|
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);
|
|
|
|
return single_element_emplace(std::move(cmd));
|
|
}
|
|
|
|
std::vector<Command> LaunchMetrics() {
|
|
return single_element_emplace(Command(MetricsBinary()));
|
|
}
|
|
|
|
std::vector<Command> LaunchGnssGrpcProxyServerIfEnabled(
|
|
const CuttlefishConfig& config) {
|
|
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());
|
|
}
|
|
return single_element_emplace(std::move(gnss_grpc_proxy_cmd));
|
|
}
|
|
|
|
std::vector<Command> LaunchBluetoothConnector(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());
|
|
return single_element_emplace(std::move(command));
|
|
}
|
|
|
|
std::vector<Command> LaunchSecureEnvironment(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);
|
|
|
|
return single_element_emplace(std::move(command));
|
|
}
|
|
|
|
std::vector<Command> LaunchVehicleHalServerIfEnabled(
|
|
const CuttlefishConfig& config) {
|
|
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);
|
|
return single_element_emplace(std::move(grpc_server));
|
|
}
|
|
|
|
std::vector<Command> LaunchConsoleForwarderIfEnabled(
|
|
const CuttlefishConfig& config) {
|
|
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);
|
|
return single_element_emplace(std::move(console_forwarder_cmd));
|
|
}
|
|
|
|
} // namespace cuttlefish
|