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
30 namespace cuttlefish {
31 namespace {
32
MacCrosvmArgument(std::optional<std::string_view> mac)33 std::string MacCrosvmArgument(std::optional<std::string_view> mac) {
34 return mac.has_value() ? fmt::format(",mac={}", mac.value()) : "";
35 }
36
PciCrosvmArgument(std::optional<pci::Address> pci)37 std::string PciCrosvmArgument(std::optional<pci::Address> pci) {
38 return pci.has_value() ? fmt::format(",pci-address={}", pci.value().Id()) : "";
39 }
40
41 }
42
CrosvmBuilder()43 CrosvmBuilder::CrosvmBuilder() : command_("crosvm") {}
44
ApplyProcessRestarter(const std::string & crosvm_binary,const std::string & first_time_argument,int exit_code)45 void CrosvmBuilder::ApplyProcessRestarter(
46 const std::string& crosvm_binary, const std::string& first_time_argument,
47 int exit_code) {
48 command_.SetExecutableAndName(ProcessRestarterBinary());
49 command_.AddParameter("-when_exited_with_code=", exit_code);
50 command_.AddParameter("-ignore_sigtstp");
51 if (!first_time_argument.empty()) {
52 command_.AddParameter("-first_time_argument=", first_time_argument);
53 }
54 command_.AddParameter("--");
55 command_.AddParameter(crosvm_binary);
56 // Flag allows exit codes other than 0 or 1, must be before command argument
57 command_.AddParameter("--extended-status");
58 }
59
AddControlSocket(const std::string & control_socket,const std::string & executable_path)60 void CrosvmBuilder::AddControlSocket(const std::string& control_socket,
61 const std::string& executable_path) {
62 auto stopper = [executable_path, control_socket]() {
63 Command stop_cmd(executable_path);
64 stop_cmd.AddParameter("stop");
65 stop_cmd.AddParameter(control_socket);
66 return stop_cmd.Start().Wait() == 0 ? StopperResult::kStopSuccess
67 : StopperResult::kStopFailure;
68 };
69 command_.SetStopper(KillSubprocessFallback(stopper));
70 command_.AddParameter("--socket=", control_socket);
71 }
72
73 // TODO: b/243198718 - switch to virtio-console
AddHvcSink()74 void CrosvmBuilder::AddHvcSink() {
75 command_.AddParameter(
76 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_, ",type=sink");
77 }
AddHvcReadOnly(const std::string & output,bool console)78 void CrosvmBuilder::AddHvcReadOnly(const std::string& output, bool console) {
79 command_.AddParameter(
80 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_,
81 ",type=file,path=", output, console ? ",console=true" : "");
82 }
AddHvcReadWrite(const std::string & output,const std::string & input)83 void CrosvmBuilder::AddHvcReadWrite(const std::string& output,
84 const std::string& input) {
85 command_.AddParameter(
86 "--serial=hardware=legacy-virtio-console,num=", ++hvc_num_,
87 ",type=file,path=", output, ",input=", input);
88 }
89
AddReadOnlyDisk(const std::string & path)90 void CrosvmBuilder::AddReadOnlyDisk(const std::string& path) {
91 command_.AddParameter("--disk=", path);
92 }
93
AddReadWriteDisk(const std::string & path)94 void CrosvmBuilder::AddReadWriteDisk(const std::string& path) {
95 command_.AddParameter("--rwdisk=", path);
96 }
97
AddSerialSink()98 void CrosvmBuilder::AddSerialSink() {
99 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
100 ",type=sink");
101 }
AddSerialConsoleReadOnly(const std::string & output)102 void CrosvmBuilder::AddSerialConsoleReadOnly(const std::string& output) {
103 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
104 ",type=file,path=", output, ",earlycon=true");
105 }
AddSerialConsoleReadWrite(const std::string & output,const std::string & input,bool earlycon)106 void CrosvmBuilder::AddSerialConsoleReadWrite(const std::string& output,
107 const std::string& input,
108 bool earlycon) {
109 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
110 ",type=file,path=", output, ",input=", input,
111 earlycon ? ",earlycon=true" : "");
112 }
AddSerial(const std::string & output,const std::string & input)113 void CrosvmBuilder::AddSerial(const std::string& output,
114 const std::string& input) {
115 command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
116 ",type=file,path=", output, ",input=", input);
117 }
118
119 #ifdef __linux__
AddTap(const std::string & tap_name,std::optional<std::string_view> mac,const std::optional<pci::Address> & pci)120 SharedFD CrosvmBuilder::AddTap(const std::string& tap_name,
121 std::optional<std::string_view> mac,
122 const std::optional<pci::Address>& pci) {
123 auto tap_fd = OpenTapInterface(tap_name);
124 if (tap_fd->IsOpen()) {
125 command_.AddParameter("--net=tap-fd=", tap_fd, MacCrosvmArgument(mac), PciCrosvmArgument(pci));
126 } else {
127 LOG(ERROR) << "Unable to connect to \"" << tap_name
128 << "\": " << tap_fd->StrError();
129 }
130 return tap_fd;
131 }
132
133 #endif
134
HvcNum()135 int CrosvmBuilder::HvcNum() { return hvc_num_; }
136
SetToRestoreFromSnapshot(const std::string & snapshot_dir_path,const std::string & instance_id_in_str,const std::string & snapshot_name)137 Result<void> CrosvmBuilder::SetToRestoreFromSnapshot(
138 const std::string& snapshot_dir_path, const std::string& instance_id_in_str,
139 const std::string& snapshot_name) {
140 auto meta_info_json = CF_EXPECT(LoadMetaJson(snapshot_dir_path));
141 const std::vector<std::string> selectors{kGuestSnapshotField,
142 instance_id_in_str};
143 const auto guest_snapshot_dir_suffix =
144 CF_EXPECT(GetValue<std::string>(meta_info_json, selectors));
145 // guest_snapshot_dir_suffix is a relative to
146 // the snapshot_path
147 const auto restore_path = snapshot_dir_path + "/" +
148 guest_snapshot_dir_suffix + "/" +
149 kGuestSnapshotBase + snapshot_name;
150 command_.AddParameter("--restore=", restore_path);
151 return {};
152 }
153
Cmd()154 Command& CrosvmBuilder::Cmd() { return command_; }
155
156 } // namespace cuttlefish
157