blob: ea55e692e05d91c56838de696bd49b36d312b15d [file] [log] [blame]
/*
* 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/libs/vm_manager/crosvm_manager.h"
#include <string>
#include <vector>
#include <glog/logging.h>
#include "common/libs/utils/network.h"
#include "common/libs/utils/subprocess.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/vm_manager/qemu_manager.h"
namespace vm_manager {
namespace {
std::string GetControlSocketPath(const vsoc::CuttlefishConfig* config) {
return config->PerInstancePath("crosvm_control.sock");
}
void AddTapFdParameter(cvd::Command* crosvm_cmd, const std::string& tap_name) {
auto tap_fd = cvd::OpenTapInterface(tap_name);
if (tap_fd->IsOpen()) {
crosvm_cmd->AddParameter("--tap-fd=", tap_fd);
} else {
LOG(ERROR) << "Unable to connect to " << tap_name << ": "
<< tap_fd->StrError();
}
}
} // namespace
const std::string CrosvmManager::name() { return "crosvm"; }
bool CrosvmManager::ConfigureGpu(vsoc::CuttlefishConfig* config) {
// Override the default HAL search paths in all cases. We do this because
// the HAL search path allows for fallbacks, and fallbacks in conjunction
// with properities lead to non-deterministic behavior while loading the
// HALs.
if (config->gpu_mode() == vsoc::kGpuModeDrmVirgl) {
config->add_kernel_cmdline("androidboot.hardware.gralloc=minigbm");
config->add_kernel_cmdline("androidboot.hardware.hwcomposer=drm_minigbm");
config->add_kernel_cmdline("androidboot.hardware.egl=mesa");
return true;
}
if (config->gpu_mode() == vsoc::kGpuModeGuestSwiftshader) {
config->add_kernel_cmdline(
"androidboot.hardware.gralloc=cutf_ashmem");
config->add_kernel_cmdline(
"androidboot.hardware.hwcomposer=cutf_cvm_ashmem");
config->add_kernel_cmdline("androidboot.hardware.egl=swiftshader");
return true;
}
return false;
}
void CrosvmManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
// PCI domain 0, bus 0, device 1, function 0
// TODO There is no way to control this assignment with crosvm (yet)
config->add_kernel_cmdline(
"androidboot.boot_devices=pci0000:00/0000:00:01.0");
}
CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
: VmManager(config) {}
std::vector<cvd::Command> CrosvmManager::StartCommands(bool with_frontend) {
cvd::Command crosvm_cmd(config_->crosvm_binary());
crosvm_cmd.AddParameter("run");
if (config_->gpu_mode() != vsoc::kGpuModeGuestSwiftshader) {
crosvm_cmd.AddParameter("--gpu");
if (config_->wayland_socket().size()) {
crosvm_cmd.AddParameter("--wayland-sock=", config_->wayland_socket());
}
if (config_->x_display().size()) {
crosvm_cmd.AddParameter("--x-display=", config_->x_display());
}
}
if (!config_->ramdisk_image_path().empty()) {
crosvm_cmd.AddParameter("--initrd=", config_->ramdisk_image_path());
}
crosvm_cmd.AddParameter("--null-audio");
crosvm_cmd.AddParameter("--mem=", config_->memory_mb());
crosvm_cmd.AddParameter("--cpus=", config_->cpus());
crosvm_cmd.AddParameter("--params=", config_->kernel_cmdline_as_string());
for (const auto& disk : config_->virtual_disk_paths()) {
crosvm_cmd.AddParameter("--rwdisk=", disk);
}
crosvm_cmd.AddParameter("--socket=", GetControlSocketPath(config_));
if (!config_->gsi_fstab_path().empty()) {
crosvm_cmd.AddParameter("--android-fstab=", config_->gsi_fstab_path());
}
if (with_frontend) {
crosvm_cmd.AddParameter("--single-touch=", config_->touch_socket_path(), ":",
config_->x_res(), ":", config_->y_res());
crosvm_cmd.AddParameter("--keyboard=", config_->keyboard_socket_path());
}
AddTapFdParameter(&crosvm_cmd, config_->wifi_tap_name());
AddTapFdParameter(&crosvm_cmd, config_->mobile_tap_name());
// TODO remove this (use crosvm's seccomp files)
crosvm_cmd.AddParameter("--disable-sandbox");
if (config_->vsock_guest_cid() >= 2) {
crosvm_cmd.AddParameter("--cid=", config_->vsock_guest_cid());
}
// Redirect the first serial port with the kernel logs to the appropriate file
crosvm_cmd.AddParameter("--serial=num=1,type=file,path=",
config_->kernel_log_pipe_name());
// Use stdio for the second serial port, it contains the serial console.
crosvm_cmd.AddParameter("--serial=num=2,type=stdout,console=true");
// Redirect standard input and output to a couple of pipes for the console
// forwarder host process to handle.
cvd::SharedFD console_in_rd, console_in_wr, console_out_rd, console_out_wr;
if (!cvd::SharedFD::Pipe(&console_in_rd, &console_in_wr) ||
!cvd::SharedFD::Pipe(&console_out_rd, &console_out_wr)) {
LOG(ERROR) << "Failed to create console pipes for crosvm: "
<< strerror(errno);
return {};
}
crosvm_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn,
console_in_rd);
crosvm_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
console_out_wr);
cvd::Command console_cmd(config_->console_forwarder_binary());
console_cmd.AddParameter("--console_in_fd=", console_in_wr);
console_cmd.AddParameter("--console_out_fd=", console_out_rd);
// This needs to be the last parameter
crosvm_cmd.AddParameter(config_->GetKernelImageToUse());
std::vector<cvd::Command> ret;
ret.push_back(std::move(crosvm_cmd));
ret.push_back(std::move(console_cmd));
return ret;
}
bool CrosvmManager::Stop() {
cvd::Command command(config_->crosvm_binary());
command.AddParameter("stop");
command.AddParameter(GetControlSocketPath(config_));
auto process = command.Start();
return process.Wait() == 0;
}
} // namespace vm_manager