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 
22 #include "common/libs/utils/network.h"
23 #include "common/libs/utils/subprocess.h"
24 #include "host/libs/config/cuttlefish_config.h"
25 #include "host/libs/config/known_paths.h"
26 
27 namespace cuttlefish {
28 
CrosvmBuilder()29 CrosvmBuilder::CrosvmBuilder() : command_("crosvm") {}
30 
ApplyProcessRestarter(const std::string & crosvm_binary,int exit_code)31 void CrosvmBuilder::ApplyProcessRestarter(const std::string& crosvm_binary,
32                                           int exit_code) {
33   command_.SetExecutableAndName(ProcessRestarterBinary());
34   command_.AddParameter("-when_exited_with_code=", exit_code);
35   command_.AddParameter("--");
36   command_.AddParameter(crosvm_binary);
37   // Flag allows exit codes other than 0 or 1, must be before command argument
38   command_.AddParameter("--extended-status");
39 }
40 
AddControlSocket(const std::string & control_socket,const std::string & executable_path)41 void CrosvmBuilder::AddControlSocket(const std::string& control_socket,
42                                      const std::string& executable_path) {
43   command_.SetStopper([executable_path, control_socket](Subprocess* proc) {
44     Command stop_cmd(executable_path);
45     stop_cmd.AddParameter("stop");
46     stop_cmd.AddParameter(control_socket);
47     if (stop_cmd.Start().Wait() == 0) {
48       return StopperResult::kStopSuccess;
49     }
50     LOG(WARNING) << "Failed to stop VMM nicely, attempting to KILL";
51     return KillSubprocess(proc) == StopperResult::kStopSuccess
52                ? StopperResult::kStopCrash
53                : StopperResult::kStopFailure;
54   });
55   command_.AddParameter("--socket=", control_socket);
56 }
57 
AddHvcSink()58 void CrosvmBuilder::AddHvcSink() {
59   command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
60                         ",type=sink");
61 }
AddHvcReadOnly(const std::string & output,bool console)62 void CrosvmBuilder::AddHvcReadOnly(const std::string& output, bool console) {
63   command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
64                         ",type=file,path=", output,
65                         console ? ",console=true" : "");
66 }
AddHvcReadWrite(const std::string & output,const std::string & input)67 void CrosvmBuilder::AddHvcReadWrite(const std::string& output,
68                                     const std::string& input) {
69   command_.AddParameter("--serial=hardware=virtio-console,num=", ++hvc_num_,
70                         ",type=file,path=", output, ",input=", input);
71 }
72 
AddReadOnlyDisk(const std::string & path)73 void CrosvmBuilder::AddReadOnlyDisk(const std::string& path) {
74   command_.AddParameter("--disk=", path);
75 }
76 
AddReadWriteDisk(const std::string & path)77 void CrosvmBuilder::AddReadWriteDisk(const std::string& path) {
78   command_.AddParameter("--rwdisk=", path);
79 }
80 
AddSerialSink()81 void CrosvmBuilder::AddSerialSink() {
82   command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
83                         ",type=sink");
84 }
AddSerialConsoleReadOnly(const std::string & output)85 void CrosvmBuilder::AddSerialConsoleReadOnly(const std::string& output) {
86   command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
87                         ",type=file,path=", output, ",earlycon=true");
88 }
AddSerialConsoleReadWrite(const std::string & output,const std::string & input,bool earlycon)89 void CrosvmBuilder::AddSerialConsoleReadWrite(const std::string& output,
90                                               const std::string& input,
91                                               bool earlycon) {
92   command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
93                         ",type=file,path=", output, ",input=", input,
94                         earlycon ? ",earlycon=true" : "");
95 }
AddSerial(const std::string & output,const std::string & input)96 void CrosvmBuilder::AddSerial(const std::string& output,
97                               const std::string& input) {
98   command_.AddParameter("--serial=hardware=serial,num=", ++serial_num_,
99                         ",type=file,path=", output, ",input=", input);
100 }
101 
AddTap(const std::string & tap_name)102 SharedFD CrosvmBuilder::AddTap(const std::string& tap_name) {
103   auto tap_fd = OpenTapInterface(tap_name);
104   if (tap_fd->IsOpen()) {
105     command_.AddParameter("--net=tap-fd=", tap_fd);
106   } else {
107     LOG(ERROR) << "Unable to connect to \"" << tap_name
108                << "\": " << tap_fd->StrError();
109   }
110   return tap_fd;
111 }
112 
AddTap(const std::string & tap_name,const std::string & mac)113 SharedFD CrosvmBuilder::AddTap(const std::string& tap_name, const std::string& mac) {
114   auto tap_fd = OpenTapInterface(tap_name);
115   if (tap_fd->IsOpen()) {
116     command_.AddParameter("--net=tap-fd=", tap_fd, ",mac=\"", mac, "\"");
117   } else {
118     LOG(ERROR) << "Unable to connect to \"" << tap_name
119                << "\": " << tap_fd->StrError();
120   }
121   return tap_fd;
122 }
123 
HvcNum()124 int CrosvmBuilder::HvcNum() { return hvc_num_; }
125 
Cmd()126 Command& CrosvmBuilder::Cmd() { return command_; }
127 
128 }  // namespace cuttlefish
129