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
CrosvmBuilder()44 CrosvmBuilder::CrosvmBuilder() : command_("crosvm") {}
45
ApplyProcessRestarter(const std::string & crosvm_binary,const std::string & first_time_argument,int exit_code)46 void CrosvmBuilder::ApplyProcessRestarter(
47 const std::string& crosvm_binary, const std::string& first_time_argument,
48 int exit_code) {
49 command_.SetExecutableAndName(ProcessRestarterBinary());
50 command_.AddParameter("-when_exited_with_code=", exit_code);
51 command_.AddParameter("-ignore_sigtstp");
52 if (!first_time_argument.empty()) {
53 command_.AddParameter("-first_time_argument=", first_time_argument);
54 }
55 command_.AddParameter("--");
56 command_.AddParameter(crosvm_binary);
57 // Flag allows exit codes other than 0 or 1, must be before command argument
58 command_.AddParameter("--extended-status");
59 }
60
AddControlSocket(const std::string & control_socket,const std::string & executable_path)61 void CrosvmBuilder::AddControlSocket(const std::string& control_socket,
62 const std::string& executable_path) {
63 auto stopper = [executable_path, control_socket]() {
64 Command stop_cmd(executable_path);
65 stop_cmd.AddParameter("stop");
66 stop_cmd.AddParameter(control_socket);
67 return stop_cmd.Start().Wait() == 0 ? StopperResult::kStopSuccess
68 : StopperResult::kStopFailure;
69 };
70 command_.SetStopper(KillSubprocessFallback(stopper));
71 command_.AddParameter("--socket=", control_socket);
72 }
73
AddCpus(size_t cpus,const std::string & vcpu_config_path)74 Result<void> CrosvmBuilder::AddCpus(size_t cpus,
75 const std::string& vcpu_config_path) {
76 if (!vcpu_config_path.empty()) {
77 Json::Value vcpu_config_json = CF_EXPECT(LoadFromFile(vcpu_config_path));
78
79 CF_EXPECT(AddCpus(vcpu_config_json));
80 } else {
81 AddCpus(cpus);
82 }
83 return {};
84 }
85
AddCpus(const Json::Value & vcpu_config_json)86 Result<void> CrosvmBuilder::AddCpus(const Json::Value& vcpu_config_json) {
87 std::vector<std::string> cpu_args =
88 CF_EXPECT(CrosvmCpuArguments(vcpu_config_json));
89
90 for (const std::string& cpu_arg : cpu_args) {
91 command_.AddParameter(cpu_arg);
92 }
93 return {};
94 }
95
AddCpus(size_t cpus)96 void CrosvmBuilder::AddCpus(size_t cpus) {
97 command_.AddParameter("--cpus=", cpus);
98 }
99
100 // TODO: b/243198718 - switch to virtio-console
AddHvcSink()101 void CrosvmBuilder::AddHvcSink() {
102 command_.AddParameter(
103 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_, ",type=sink");
104 }
AddHvcReadOnly(const std::string & output,bool console)105 void CrosvmBuilder::AddHvcReadOnly(const std::string& output, bool console) {
106 command_.AddParameter(
107 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_,
108 ",type=file,path=", output, 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(
113 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_,
114 ",type=file,path=", output, ",input=", input);
115 }
116
AddReadOnlyDisk(const std::string & path)117 void CrosvmBuilder::AddReadOnlyDisk(const std::string& path) {
118 command_.AddParameter("--block=path=", path, ",ro=true");
119 }
120
AddReadWriteDisk(const std::string & path)121 void CrosvmBuilder::AddReadWriteDisk(const std::string& path) {
122 command_.AddParameter("--block=path=", path);
123 }
124
AddSerialSink()125 void CrosvmBuilder::AddSerialSink() {
126 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
127 ",type=sink");
128 }
AddSerialConsoleReadOnly(const std::string & output)129 void CrosvmBuilder::AddSerialConsoleReadOnly(const std::string& output) {
130 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
131 ",type=file,path=", output, ",earlycon=true");
132 }
AddSerialConsoleReadWrite(const std::string & output,const std::string & input,bool earlycon)133 void CrosvmBuilder::AddSerialConsoleReadWrite(const std::string& output,
134 const std::string& input,
135 bool earlycon) {
136 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
137 ",type=file,path=", output, ",input=", input,
138 earlycon ? ",earlycon=true" : "");
139 }
AddSerial(const std::string & output,const std::string & input)140 void CrosvmBuilder::AddSerial(const std::string& output,
141 const std::string& input) {
142 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
143 ",type=file,path=", output, ",input=", input);
144 }
145
146 #ifdef __linux__
AddTap(const std::string & tap_name,std::optional<std::string_view> mac,const std::optional<pci::Address> & pci)147 void CrosvmBuilder::AddTap(const std::string& tap_name,
148 std::optional<std::string_view> mac,
149 const std::optional<pci::Address>& pci) {
150 command_.AddParameter("--net=tap-name=", tap_name, MacCrosvmArgument(mac),
151 PciCrosvmArgument(pci));
152 }
153
154 #endif
155
HvcNum()156 int CrosvmBuilder::HvcNum() { return hvc_num_; }
157
Cmd()158 Command& CrosvmBuilder::Cmd() { return command_; }
159
160 } // namespace cuttlefish
161