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