1 /*
2 * Copyright (C) 2017 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
17 #include "host/commands/run_cvd/server_loop.h"
18
19 #include <gflags/gflags.h>
20 #include <unistd.h>
21 #include <string>
22
23 #include "common/libs/fs/shared_buf.h"
24 #include "common/libs/utils/files.h"
25 #include "common/libs/utils/subprocess.h"
26 #include "host/commands/run_cvd/runner_defs.h"
27 #include "host/libs/config/cuttlefish_config.h"
28 #include "host/libs/config/data_image.h"
29
30 namespace cuttlefish {
31
32 namespace {
33
CreateQcowOverlay(const std::string & crosvm_path,const std::string & backing_file,const std::string & output_overlay_path)34 bool CreateQcowOverlay(const std::string& crosvm_path,
35 const std::string& backing_file,
36 const std::string& output_overlay_path) {
37 Command crosvm_qcow2_cmd(crosvm_path);
38 crosvm_qcow2_cmd.AddParameter("create_qcow2");
39 crosvm_qcow2_cmd.AddParameter("--backing_file=", backing_file);
40 crosvm_qcow2_cmd.AddParameter(output_overlay_path);
41 int success = crosvm_qcow2_cmd.Start().Wait();
42 if (success != 0) {
43 LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
44 << success;
45 return false;
46 }
47 return true;
48 }
49
DeleteFifos(const CuttlefishConfig::InstanceSpecific & instance)50 void DeleteFifos(const CuttlefishConfig::InstanceSpecific& instance) {
51 // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
52 std::vector<std::string> pipes = {
53 instance.kernel_log_pipe_name(),
54 instance.console_in_pipe_name(),
55 instance.console_out_pipe_name(),
56 instance.logcat_pipe_name(),
57 instance.PerInstanceInternalPath("keymaster_fifo_vm.in"),
58 instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
59 instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
60 instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
61 instance.PerInstanceInternalPath("bt_fifo_vm.in"),
62 instance.PerInstanceInternalPath("bt_fifo_vm.out"),
63 };
64 for (const auto& pipe : pipes) {
65 unlink(pipe.c_str());
66 }
67 }
68
PowerwashFiles()69 bool PowerwashFiles() {
70 auto config = CuttlefishConfig::Get();
71 if (!config) {
72 LOG(ERROR) << "Could not load the config.";
73 return false;
74 }
75 auto instance = config->ForDefaultInstance();
76
77 DeleteFifos(instance);
78
79 // TODO(schuffelen): Clean up duplication with assemble_cvd
80 auto kregistry_path = instance.access_kregistry_path();
81 unlink(kregistry_path.c_str());
82 CreateBlankImage(kregistry_path, 2 /* mb */, "none");
83
84 auto pstore_path = instance.pstore_path();
85 unlink(pstore_path.c_str());
86 CreateBlankImage(pstore_path, 2 /* mb */, "none");
87
88 auto sdcard_path = instance.sdcard_path();
89 auto sdcard_size = FileSize(sdcard_path);
90 unlink(sdcard_path.c_str());
91 // round up
92 auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
93 LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
94 CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
95
96 auto overlay_path = instance.PerInstancePath("overlay.img");
97 unlink(overlay_path.c_str());
98 if (!CreateQcowOverlay(config->crosvm_binary(),
99 instance.os_composite_disk_path(), overlay_path)) {
100 LOG(ERROR) << "CreateQcowOverlay failed";
101 return false;
102 }
103 return true;
104 }
105
RestartRunCvd(const CuttlefishConfig & config,int notification_fd)106 void RestartRunCvd(const CuttlefishConfig& config, int notification_fd) {
107 auto config_path = config.AssemblyPath("cuttlefish_config.json");
108 auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
109 WriteAll(followup_stdin, config_path + "\n");
110 followup_stdin->LSeek(0, SEEK_SET);
111 followup_stdin->UNMANAGED_Dup2(0);
112
113 auto argv_vec = gflags::GetArgvs();
114 char** argv = new char*[argv_vec.size() + 2];
115 for (size_t i = 0; i < argv_vec.size(); i++) {
116 argv[i] = argv_vec[i].data();
117 }
118 // Will take precedence over any earlier arguments.
119 std::string reboot_notification =
120 "-reboot_notification_fd=" + std::to_string(notification_fd);
121 argv[argv_vec.size()] = reboot_notification.data();
122 argv[argv_vec.size() + 1] = nullptr;
123
124 execv("/proc/self/exe", argv);
125 // execve should not return, so something went wrong.
126 PLOG(ERROR) << "execv returned: ";
127 }
128
129 } // namespace
130
ServerLoop(SharedFD server,ProcessMonitor * process_monitor)131 void ServerLoop(SharedFD server, ProcessMonitor* process_monitor) {
132 while (true) {
133 // TODO: use select to handle simultaneous connections.
134 auto client = SharedFD::Accept(*server);
135 LauncherAction action;
136 while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) {
137 switch (action) {
138 case LauncherAction::kStop:
139 if (process_monitor->StopMonitoredProcesses()) {
140 auto response = LauncherResponse::kSuccess;
141 client->Write(&response, sizeof(response));
142 std::exit(0);
143 } else {
144 auto response = LauncherResponse::kError;
145 client->Write(&response, sizeof(response));
146 }
147 break;
148 case LauncherAction::kStatus: {
149 // TODO(schuffelen): Return more information on a side channel
150 auto response = LauncherResponse::kSuccess;
151 client->Write(&response, sizeof(response));
152 break;
153 }
154 case LauncherAction::kPowerwash: {
155 LOG(INFO) << "Received a Powerwash request from the monitor socket";
156 if (!process_monitor->StopMonitoredProcesses()) {
157 LOG(ERROR) << "Stopping processes failed.";
158 auto response = LauncherResponse::kError;
159 client->Write(&response, sizeof(response));
160 break;
161 }
162 if (!PowerwashFiles()) {
163 LOG(ERROR) << "Powerwashing files failed.";
164 auto response = LauncherResponse::kError;
165 client->Write(&response, sizeof(response));
166 break;
167 }
168 auto response = LauncherResponse::kSuccess;
169 client->Write(&response, sizeof(response));
170
171 auto config = CuttlefishConfig::Get();
172 CHECK(config) << "Could not load config";
173 RestartRunCvd(*config, client->UNMANAGED_Dup());
174 // RestartRunCvd should not return, so something went wrong.
175 response = LauncherResponse::kError;
176 client->Write(&response, sizeof(response));
177 LOG(FATAL) << "run_cvd in a bad state";
178 break;
179 }
180 case LauncherAction::kRestart: {
181 if (!process_monitor->StopMonitoredProcesses()) {
182 LOG(ERROR) << "Stopping processes failed.";
183 auto response = LauncherResponse::kError;
184 client->Write(&response, sizeof(response));
185 break;
186 }
187
188 auto config = CuttlefishConfig::Get();
189 CHECK(config) << "Could not load config";
190 auto instance = config->ForDefaultInstance();
191 DeleteFifos(instance);
192
193 auto response = LauncherResponse::kSuccess;
194 client->Write(&response, sizeof(response));
195 CHECK(config) << "Could not load config";
196 RestartRunCvd(*config, client->UNMANAGED_Dup());
197 // RestartRunCvd should not return, so something went wrong.
198 response = LauncherResponse::kError;
199 client->Write(&response, sizeof(response));
200 LOG(FATAL) << "run_cvd in a bad state";
201 break;
202 }
203 default:
204 LOG(ERROR) << "Unrecognized launcher action: "
205 << static_cast<char>(action);
206 auto response = LauncherResponse::kError;
207 client->Write(&response, sizeof(response));
208 }
209 }
210 }
211 }
212
213 } // namespace cuttlefish
214