1 //
2 // Copyright (C) 2021 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 #include "host/libs/vm_manager/crosvm_builder.h"
17
18 #include <android-base/logging.h>
19
20 #include <string>
21 #include <vector>
22
23 #include "common/libs/utils/json.h"
24 #include "common/libs/utils/network.h"
25 #include "common/libs/utils/subprocess.h"
26 #include "host/libs/command_util/snapshot_utils.h"
27 #include "host/libs/config/cuttlefish_config.h"
28 #include "host/libs/config/known_paths.h"
29 #include "host/libs/vm_manager/crosvm_cpu.h"
30
31 namespace cuttlefish {
32 namespace {
33
MacCrosvmArgument(std::optional<std::string_view> mac)34 std::string MacCrosvmArgument(std::optional<std::string_view> mac) {
35 return mac.has_value() ? fmt::format(",mac={}", mac.value()) : "";
36 }
37
PciCrosvmArgument(std::optional<pci::Address> pci)38 std::string PciCrosvmArgument(std::optional<pci::Address> pci) {
39 return pci.has_value() ? fmt::format(",pci-address={}", pci.value().Id())
40 : "";
41 }
42
43 } // namespace
44
CrosvmBuilder()45 CrosvmBuilder::CrosvmBuilder() : command_("crosvm") {}
46
ApplyProcessRestarter(const std::string & crosvm_binary,const std::string & first_time_argument,int exit_code)47 void CrosvmBuilder::ApplyProcessRestarter(
48 const std::string& crosvm_binary, const std::string& first_time_argument,
49 int exit_code) {
50 command_.SetExecutableAndName(ProcessRestarterBinary());
51 command_.AddParameter("-when_exited_with_code=", exit_code);
52 command_.AddParameter("-ignore_sigtstp");
53 if (!first_time_argument.empty()) {
54 command_.AddParameter("-first_time_argument=", first_time_argument);
55 }
56 command_.AddParameter("--");
57 command_.AddParameter(crosvm_binary);
58 // Flag allows exit codes other than 0 or 1, must be before command argument
59 command_.AddParameter("--extended-status");
60 }
61
AddControlSocket(const std::string & control_socket,const std::string & executable_path)62 void CrosvmBuilder::AddControlSocket(const std::string& control_socket,
63 const std::string& executable_path) {
64 auto stopper = [executable_path, control_socket]() {
65 Command stop_cmd(executable_path);
66 stop_cmd.AddParameter("stop");
67 stop_cmd.AddParameter(control_socket);
68 return stop_cmd.Start().Wait() == 0 ? StopperResult::kStopSuccess
69 : StopperResult::kStopFailure;
70 };
71 command_.SetStopper(KillSubprocessFallback(stopper));
72 command_.AddParameter("--socket=", control_socket);
73 }
74
AddCpus(size_t cpus,const std::string & vcpu_config_path)75 Result<void> CrosvmBuilder::AddCpus(size_t cpus,
76 const std::string& vcpu_config_path) {
77 if (!vcpu_config_path.empty()) {
78 Json::Value vcpu_config_json = CF_EXPECT(LoadFromFile(vcpu_config_path));
79
80 CF_EXPECT(AddCpus(vcpu_config_json));
81 } else {
82 AddCpus(cpus);
83 }
84 return {};
85 }
86
AddCpus(const Json::Value & vcpu_config_json)87 Result<void> CrosvmBuilder::AddCpus(const Json::Value& vcpu_config_json) {
88 std::vector<std::string> cpu_args =
89 CF_EXPECT(CrosvmCpuArguments(vcpu_config_json));
90
91 for (const std::string& cpu_arg : cpu_args) {
92 command_.AddParameter(cpu_arg);
93 }
94 return {};
95 }
96
AddCpus(size_t cpus)97 void CrosvmBuilder::AddCpus(size_t cpus) {
98 command_.AddParameter("--cpus=", cpus);
99 }
100
AddHvcSink()101 void CrosvmBuilder::AddHvcSink() {
102 command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
103 ",type=sink");
104 }
AddHvcReadOnly(const std::string & output,bool console)105 void CrosvmBuilder::AddHvcReadOnly(const std::string& output, bool console) {
106 command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
107 ",type=file,path=", output,
108 console ? ",console=true" : "");
109 }
AddHvcReadWrite(const std::string & output,const std::string & input)110 void CrosvmBuilder::AddHvcReadWrite(const std::string& output,
111 const std::string& input) {
112 command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
113 ",type=file,path=", output, ",input=", input);
114 }
AddHvcSocket(const std::string & socket)115 void CrosvmBuilder::AddHvcSocket(const std::string& socket) {
116 command_.AddParameter(
117 "--serial=hardware=virtio-console,num=", ++hvc_num_,
118 ",type=unix-stream,input-unix-stream=true,path=", socket);
119 }
120
AddKvmPath(const std::string & path)121 void CrosvmBuilder::AddKvmPath(const std::string& path) {
122 command_.AddParameter("--hypervisor=kvm[device=", path, "]");
123 }
124
AddReadOnlyDisk(const std::string & path)125 void CrosvmBuilder::AddReadOnlyDisk(const std::string& path) {
126 command_.AddParameter("--block=path=", path, ",ro=true");
127 }
128
AddReadWriteDisk(const std::string & path)129 void CrosvmBuilder::AddReadWriteDisk(const std::string& path) {
130 command_.AddParameter("--block=path=", path);
131 }
132
AddSerialSink()133 void CrosvmBuilder::AddSerialSink() {
134 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
135 ",type=sink");
136 }
AddSerialConsoleReadOnly(const std::string & output)137 void CrosvmBuilder::AddSerialConsoleReadOnly(const std::string& output) {
138 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
139 ",type=file,path=", output, ",earlycon=true");
140 }
AddSerialConsoleReadWrite(const std::string & output,const std::string & input,bool earlycon)141 void CrosvmBuilder::AddSerialConsoleReadWrite(const std::string& output,
142 const std::string& input,
143 bool earlycon) {
144 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
145 ",type=file,path=", output, ",input=", input,
146 earlycon ? ",earlycon=true" : "");
147 }
AddSerial(const std::string & output,const std::string & input)148 void CrosvmBuilder::AddSerial(const std::string& output,
149 const std::string& input) {
150 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
151 ",type=file,path=", output, ",input=", input);
152 }
153
154 #ifdef __linux__
AddTap(const std::string & tap_name,std::optional<std::string_view> mac,const std::optional<pci::Address> & pci)155 void CrosvmBuilder::AddTap(const std::string& tap_name,
156 std::optional<std::string_view> mac,
157 const std::optional<pci::Address>& pci) {
158 command_.AddParameter("--net=tap-name=", tap_name, MacCrosvmArgument(mac),
159 PciCrosvmArgument(pci));
160 }
161 #endif
162
AddVhostUser(const std::string & type,const std::string & socket_path,int max_queue_size)163 void CrosvmBuilder::AddVhostUser(const std::string& type,
164 const std::string& socket_path,
165 int max_queue_size) {
166 command_.AddParameter("--vhost-user=type=", type, ",socket=", socket_path,
167 ",max-queue-size=", max_queue_size);
168 }
169
HvcNum()170 int CrosvmBuilder::HvcNum() { return hvc_num_; }
171
Cmd()172 Command& CrosvmBuilder::Cmd() { return command_; }
173
174 } // namespace cuttlefish
175