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 <unistd.h>
20
21 #include <algorithm>
22 #include <memory>
23 #include <string>
24
25 #include <fruit/fruit.h>
26 #include <gflags/gflags.h>
27
28 #include "common/libs/fs/shared_buf.h"
29 #include "common/libs/utils/files.h"
30 #include "common/libs/utils/subprocess.h"
31 #include "host/commands/run_cvd/runner_defs.h"
32 #include "host/libs/config/command_source.h"
33 #include "host/libs/config/cuttlefish_config.h"
34 #include "host/libs/config/data_image.h"
35 #include "host/libs/config/feature.h"
36 #include "host/libs/config/inject.h"
37
38 namespace cuttlefish {
39
40 namespace {
41
CreateQcowOverlay(const std::string & crosvm_path,const std::string & backing_file,const std::string & output_overlay_path)42 bool CreateQcowOverlay(const std::string& crosvm_path,
43 const std::string& backing_file,
44 const std::string& output_overlay_path) {
45 Command crosvm_qcow2_cmd(crosvm_path);
46 crosvm_qcow2_cmd.AddParameter("create_qcow2");
47 crosvm_qcow2_cmd.AddParameter("--backing-file");
48 crosvm_qcow2_cmd.AddParameter(backing_file);
49 crosvm_qcow2_cmd.AddParameter(output_overlay_path);
50 int success = crosvm_qcow2_cmd.Start().Wait();
51 if (success != 0) {
52 LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
53 << success;
54 return false;
55 }
56 return true;
57 }
58
59 class ServerLoopImpl : public ServerLoop,
60 public SetupFeature,
61 public LateInjected {
62 public:
INJECT(ServerLoopImpl (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance))63 INJECT(ServerLoopImpl(const CuttlefishConfig& config,
64 const CuttlefishConfig::InstanceSpecific& instance))
65 : config_(config), instance_(instance) {}
66
LateInject(fruit::Injector<> & injector)67 Result<void> LateInject(fruit::Injector<>& injector) override {
68 command_sources_ = injector.getMultibindings<CommandSource>();
69 return {};
70 }
71
72 // ServerLoop
Run()73 Result<void> Run() override {
74 // Monitor and restart host processes supporting the CVD
75 ProcessMonitor::Properties process_monitor_properties;
76 process_monitor_properties.RestartSubprocesses(
77 instance_.restart_subprocesses());
78
79 for (auto& command_source : command_sources_) {
80 if (command_source->Enabled()) {
81 auto commands = CF_EXPECT(command_source->Commands());
82 process_monitor_properties.AddCommands(std::move(commands));
83 }
84 }
85
86 ProcessMonitor process_monitor(std::move(process_monitor_properties));
87
88 CF_EXPECT(process_monitor.StartAndMonitorProcesses());
89
90 while (true) {
91 // TODO: use select to handle simultaneous connections.
92 auto client = SharedFD::Accept(*server_);
93 LauncherAction action;
94 while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) {
95 switch (action) {
96 case LauncherAction::kStop: {
97 auto stop = process_monitor.StopMonitoredProcesses();
98 if (stop.ok()) {
99 auto response = LauncherResponse::kSuccess;
100 client->Write(&response, sizeof(response));
101 std::exit(0);
102 } else {
103 LOG(ERROR) << "Failed to stop subprocesses:\n"
104 << stop.error().Message();
105 LOG(DEBUG) << "Failed to stop subprocesses:\n"
106 << stop.error().Trace();
107 auto response = LauncherResponse::kError;
108 client->Write(&response, sizeof(response));
109 }
110 break;
111 }
112 case LauncherAction::kStatus: {
113 // TODO(schuffelen): Return more information on a side channel
114 auto response = LauncherResponse::kSuccess;
115 client->Write(&response, sizeof(response));
116 break;
117 }
118 case LauncherAction::kPowerwash: {
119 LOG(INFO) << "Received a Powerwash request from the monitor socket";
120 const auto& disks = instance_.virtual_disk_paths();
121 auto overlay = instance_.PerInstancePath("overlay.img");
122 if (std::find(disks.begin(), disks.end(), overlay) == disks.end()) {
123 LOG(ERROR) << "Powerwash unsupported with --use_overlay=false";
124 auto response = LauncherResponse::kError;
125 client->Write(&response, sizeof(response));
126 break;
127 }
128
129 auto stop = process_monitor.StopMonitoredProcesses();
130 if (!stop.ok()) {
131 LOG(ERROR) << "Stopping processes failed:\n"
132 << stop.error().Message();
133 LOG(DEBUG) << "Stopping processes failed:\n"
134 << stop.error().Trace();
135 auto response = LauncherResponse::kError;
136 client->Write(&response, sizeof(response));
137 break;
138 }
139 if (!PowerwashFiles()) {
140 LOG(ERROR) << "Powerwashing files failed.";
141 auto response = LauncherResponse::kError;
142 client->Write(&response, sizeof(response));
143 break;
144 }
145 auto response = LauncherResponse::kSuccess;
146 client->Write(&response, sizeof(response));
147
148 RestartRunCvd(client->UNMANAGED_Dup());
149 // RestartRunCvd should not return, so something went wrong.
150 response = LauncherResponse::kError;
151 client->Write(&response, sizeof(response));
152 LOG(FATAL) << "run_cvd in a bad state";
153 break;
154 }
155 case LauncherAction::kRestart: {
156 auto stop = process_monitor.StopMonitoredProcesses();
157 if (!stop.ok()) {
158 LOG(ERROR) << "Stopping processes failed:\n"
159 << stop.error().Message();
160 LOG(DEBUG) << "Stopping processes failed:\n"
161 << stop.error().Trace();
162 auto response = LauncherResponse::kError;
163 client->Write(&response, sizeof(response));
164 break;
165 }
166 DeleteFifos();
167
168 auto response = LauncherResponse::kSuccess;
169 client->Write(&response, sizeof(response));
170 RestartRunCvd(client->UNMANAGED_Dup());
171 // RestartRunCvd should not return, so something went wrong.
172 response = LauncherResponse::kError;
173 client->Write(&response, sizeof(response));
174 LOG(FATAL) << "run_cvd in a bad state";
175 break;
176 }
177 default:
178 LOG(ERROR) << "Unrecognized launcher action: "
179 << static_cast<char>(action);
180 auto response = LauncherResponse::kError;
181 client->Write(&response, sizeof(response));
182 }
183 }
184 }
185 }
186
187 // SetupFeature
Name() const188 std::string Name() const override { return "ServerLoop"; }
189
190 private:
Enabled() const191 bool Enabled() const override { return true; }
Dependencies() const192 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
Setup()193 bool Setup() {
194 auto launcher_monitor_path = instance_.launcher_monitor_socket_path();
195 server_ = SharedFD::SocketLocalServer(launcher_monitor_path.c_str(), false,
196 SOCK_STREAM, 0666);
197 if (!server_->IsOpen()) {
198 LOG(ERROR) << "Error when opening launcher server: "
199 << server_->StrError();
200 return false;
201 }
202 return true;
203 }
204
DeleteFifos()205 void DeleteFifos() {
206 // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
207 std::vector<std::string> pipes = {
208 instance_.kernel_log_pipe_name(),
209 instance_.console_in_pipe_name(),
210 instance_.console_out_pipe_name(),
211 instance_.logcat_pipe_name(),
212 instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"),
213 instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
214 instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
215 instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
216 instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
217 instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
218 instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
219 instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
220 instance_.PerInstanceInternalPath("bt_fifo_vm.in"),
221 instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
222 instance_.PerInstanceInternalPath("uwb_fifo_vm.in"),
223 instance_.PerInstanceInternalPath("uwb_fifo_vm.out"),
224 instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
225 instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
226 instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
227 instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
228 instance_.PerInstanceInternalPath("confui_fifo_vm.in"),
229 instance_.PerInstanceInternalPath("confui_fifo_vm.out"),
230 };
231 for (const auto& pipe : pipes) {
232 unlink(pipe.c_str());
233 }
234 }
235
PowerwashFiles()236 bool PowerwashFiles() {
237 DeleteFifos();
238
239 // TODO(b/269669405): Figure out why this file is not being deleted
240 unlink(instance_.PerInstanceInternalUdsPath("crosvm_control.sock").c_str());
241
242 // TODO(schuffelen): Clean up duplication with assemble_cvd
243 unlink(instance_.PerInstancePath("NVChip").c_str());
244
245 auto kregistry_path = instance_.access_kregistry_path();
246 unlink(kregistry_path.c_str());
247 CreateBlankImage(kregistry_path, 2 /* mb */, "none");
248
249 auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
250 unlink(hwcomposer_pmem_path.c_str());
251 CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
252
253 auto pstore_path = instance_.pstore_path();
254 unlink(pstore_path.c_str());
255 CreateBlankImage(pstore_path, 2 /* mb */, "none");
256
257 auto sdcard_path = instance_.sdcard_path();
258 auto sdcard_size = FileSize(sdcard_path);
259 unlink(sdcard_path.c_str());
260 // round up
261 auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
262 LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
263 CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
264
265 struct OverlayFile {
266 std::string name;
267 std::string composite_disk_path;
268
269 OverlayFile(std::string name, std::string composite_disk_path)
270 : name(std::move(name)), composite_disk_path(std::move(composite_disk_path)) {}
271 };
272 std::vector<OverlayFile> overlay_files{
273 OverlayFile("overlay.img", instance_.os_composite_disk_path())
274 };
275 if (instance_.ap_boot_flow() != CuttlefishConfig::InstanceSpecific::APBootFlow::None) {
276 overlay_files.emplace_back(
277 OverlayFile("ap_overlay.img", instance_.ap_composite_disk_path()));
278 }
279 for (const auto& overlay_file : overlay_files) {
280 auto overlay_path = instance_.PerInstancePath(overlay_file.name.c_str());
281 auto composite_disk_path = overlay_file.composite_disk_path.c_str();
282
283 unlink(overlay_path.c_str());
284 if (!CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path, overlay_path)) {
285 LOG(ERROR) << "CreateQcowOverlay failed";
286 return false;
287 }
288 }
289 return true;
290 }
291
RestartRunCvd(int notification_fd)292 void RestartRunCvd(int notification_fd) {
293 auto config_path = config_.AssemblyPath("cuttlefish_config.json");
294 auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
295 WriteAll(followup_stdin, config_path + "\n");
296 followup_stdin->LSeek(0, SEEK_SET);
297 followup_stdin->UNMANAGED_Dup2(0);
298
299 auto argv_vec = gflags::GetArgvs();
300 std::unique_ptr<char*[]> argv(new char*[argv_vec.size() + 2]);
301 for (size_t i = 0; i < argv_vec.size(); i++) {
302 argv[i] = argv_vec[i].data();
303 }
304 // Will take precedence over any earlier arguments.
305 std::string reboot_notification =
306 "-reboot_notification_fd=" + std::to_string(notification_fd);
307 argv[argv_vec.size()] = reboot_notification.data();
308 argv[argv_vec.size() + 1] = nullptr;
309
310 execv("/proc/self/exe", argv.get());
311 // execve should not return, so something went wrong.
312 PLOG(ERROR) << "execv returned: ";
313 }
314
315 const CuttlefishConfig& config_;
316 const CuttlefishConfig::InstanceSpecific& instance_;
317 std::vector<CommandSource*> command_sources_;
318 SharedFD server_;
319 };
320
321 } // namespace
322
323 ServerLoop::~ServerLoop() = default;
324
325 fruit::Component<fruit::Required<const CuttlefishConfig,
326 const CuttlefishConfig::InstanceSpecific>,
327 ServerLoop>
serverLoopComponent()328 serverLoopComponent() {
329 return fruit::createComponent()
330 .bind<ServerLoop, ServerLoopImpl>()
331 .addMultibinding<LateInjected, ServerLoopImpl>()
332 .addMultibinding<SetupFeature, ServerLoopImpl>();
333 }
334
335 } // namespace cuttlefish
336