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