1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/libs/vm_manager/crosvm_manager.h"
18
19 #include <string>
20 #include <vector>
21
22 #include <glog/logging.h>
23
24 #include "common/libs/utils/network.h"
25 #include "common/libs/utils/subprocess.h"
26 #include "host/libs/config/cuttlefish_config.h"
27 #include "host/libs/vm_manager/qemu_manager.h"
28
29 namespace vm_manager {
30
31 namespace {
32
GetControlSocketPath(const vsoc::CuttlefishConfig * config)33 std::string GetControlSocketPath(const vsoc::CuttlefishConfig* config) {
34 return config->PerInstancePath("crosvm_control.sock");
35 }
36
ConnectToLogMonitor(const std::string & log_monitor_name)37 cvd::SharedFD ConnectToLogMonitor(const std::string& log_monitor_name) {
38 return cvd::SharedFD::SocketLocalClient(log_monitor_name.c_str(), false,
39 SOCK_STREAM);
40 }
41
AddTapFdParameter(cvd::Command * crosvm_cmd,const std::string & tap_name)42 void AddTapFdParameter(cvd::Command* crosvm_cmd, const std::string& tap_name) {
43 auto tap_fd = cvd::OpenTapInterface(tap_name);
44 if (tap_fd->IsOpen()) {
45 crosvm_cmd->AddParameter("--tap-fd=", tap_fd);
46 } else {
47 LOG(ERROR) << "Unable to connect to " << tap_name << ": "
48 << tap_fd->StrError();
49 }
50 }
51
52 } // namespace
53
name()54 const std::string CrosvmManager::name() { return "crosvm"; }
55
ConfigureBootDevices(vsoc::CuttlefishConfig * config)56 void CrosvmManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
57 // PCI domain 0, bus 0, device 5, function 0
58 // TODO There is no way to control this assignment with crosvm (yet)
59 config->add_kernel_cmdline(
60 "androidboot.boot_devices=pci0000:00/0000:00:01.0");
61 }
62
CrosvmManager(const vsoc::CuttlefishConfig * config)63 CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
64 : VmManager(config) {}
65
StartCommand()66 cvd::Command CrosvmManager::StartCommand() {
67 // TODO Add aarch64 support
68 // TODO Add the tap interfaces (--tap-fd)
69 // TODO Redirect logcat output
70
71 // Run crosvm directly instead of through a cf_crosvm.sh script. The kernel
72 // logs are on crosvm's standard output, so we need to redirect it to the log
73 // monitor socket, a helper script will print more than just the logs to
74 // standard output.
75 cvd::Command command(config_->crosvm_binary());
76 command.AddParameter("run");
77
78 if (!config_->ramdisk_image_path().empty()) {
79 command.AddParameter("--initrd=", config_->ramdisk_image_path());
80 }
81 command.AddParameter("--null-audio");
82 command.AddParameter("--mem=", config_->memory_mb());
83 command.AddParameter("--cpus=", config_->cpus());
84 command.AddParameter("--params=", config_->kernel_cmdline_as_string());
85 if (config_->super_image_path().empty()) {
86 command.AddParameter("--rwdisk=", config_->system_image_path());
87 } else {
88 command.AddParameter("--rwdisk=", config_->super_image_path());
89 }
90 command.AddParameter("--rwdisk=", config_->data_image_path());
91 command.AddParameter("--rwdisk=", config_->cache_image_path());
92 command.AddParameter("--rwdisk=", config_->metadata_image_path());
93 if (config_->super_image_path().empty()) {
94 command.AddParameter("--rwdisk=", config_->vendor_image_path());
95 command.AddParameter("--rwdisk=", config_->product_image_path());
96 }
97 command.AddParameter("--socket=", GetControlSocketPath(config_));
98 if (!config_->gsi_fstab_path().empty()) {
99 command.AddParameter("--android-fstab=", config_->gsi_fstab_path());
100 }
101 command.AddParameter("--single-touch=", config_->touch_socket_path(), ":",
102 config_->x_res(), ":", config_->y_res());
103 command.AddParameter("--keyboard=", config_->keyboard_socket_path());
104
105 AddTapFdParameter(&command, config_->wifi_tap_name());
106 AddTapFdParameter(&command, config_->mobile_tap_name());
107
108 // TODO remove this (use crosvm's seccomp files)
109 command.AddParameter("--disable-sandbox");
110
111 if (config_->vsock_guest_cid() >= 2) {
112 command.AddParameter("--cid=", config_->vsock_guest_cid());
113 }
114
115 auto kernel_log_connection =
116 ConnectToLogMonitor(config_->kernel_log_socket_name());
117 if (!kernel_log_connection->IsOpen()) {
118 LOG(WARNING) << "Unable to connect to log monitor: "
119 << kernel_log_connection->StrError();
120 } else {
121 command.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
122 kernel_log_connection);
123 }
124
125 auto dev_null = cvd::SharedFD::Open("/dev/null", O_RDONLY);
126 if (dev_null->IsOpen()) {
127 command.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, dev_null);
128 } else {
129 LOG(ERROR) << "Unable to open /dev/null for stdin redirection";
130 }
131
132 // This needs to be the last parameter
133 command.AddParameter(config_->GetKernelImageToUse());
134
135 return command;
136 }
137
Stop()138 bool CrosvmManager::Stop() {
139 cvd::Command command(config_->crosvm_binary());
140 command.AddParameter("stop");
141 command.AddParameter(GetControlSocketPath(config_));
142
143 auto process = command.Start();
144
145 return process.Wait() == 0;
146 }
147
148 } // namespace vm_manager
149
150