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_impl.h"
18
19 #include <unistd.h>
20
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include <android-base/logging.h>
27 #include <gflags/gflags.h>
28
29 #include "common/libs/fs/shared_buf.h"
30 #include "common/libs/fs/shared_fd.h"
31 #include "common/libs/utils/files.h"
32 #include "common/libs/utils/result.h"
33 #include "common/libs/utils/subprocess.h"
34 #include "host/libs/command_util/runner/defs.h"
35 #include "host/libs/command_util/util.h"
36 #include "host/libs/config/command_source.h"
37 #include "host/libs/config/cuttlefish_config.h"
38 #include "host/libs/config/data_image.h"
39 #include "host/libs/config/inject.h"
40 #include "host/libs/process_monitor/process_monitor.h"
41
42 namespace cuttlefish {
43 namespace run_cvd_impl {
44
CreateQcowOverlay(const std::string & crosvm_path,const std::string & backing_file,const std::string & output_overlay_path)45 bool ServerLoopImpl::CreateQcowOverlay(const std::string& crosvm_path,
46 const std::string& backing_file,
47 const std::string& output_overlay_path) {
48 Command crosvm_qcow2_cmd(crosvm_path);
49 crosvm_qcow2_cmd.AddParameter("create_qcow2");
50 crosvm_qcow2_cmd.AddParameter("--backing-file");
51 crosvm_qcow2_cmd.AddParameter(backing_file);
52 crosvm_qcow2_cmd.AddParameter(output_overlay_path);
53 int success = crosvm_qcow2_cmd.Start().Wait();
54 if (success != 0) {
55 LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
56 << success;
57 return false;
58 }
59 return true;
60 }
61
ServerLoopImpl(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance,AutoSnapshotControlFiles::Type & snapshot_control_files,WebRtcController & webrtc_controller)62 ServerLoopImpl::ServerLoopImpl(
63 const CuttlefishConfig& config,
64 const CuttlefishConfig::InstanceSpecific& instance,
65 AutoSnapshotControlFiles::Type& snapshot_control_files,
66 WebRtcController& webrtc_controller)
67 : config_(config),
68 instance_(instance),
69 snapshot_control_files_(snapshot_control_files),
70 webrtc_controller_(webrtc_controller),
71 vm_name_to_control_sock_{InitializeVmToControlSockPath(instance)},
72 device_status_{DeviceStatus::kUnknown} {}
73
LateInject(fruit::Injector<> & injector)74 Result<void> ServerLoopImpl::LateInject(fruit::Injector<>& injector) {
75 command_sources_ = injector.getMultibindings<CommandSource>();
76 return {};
77 }
78
Run()79 Result<void> ServerLoopImpl::Run() {
80 // Monitor and restart host processes supporting the CVD
81 auto process_monitor_properties = ProcessMonitor::Properties();
82 process_monitor_properties.RestartSubprocesses(
83 instance_.restart_subprocesses());
84 process_monitor_properties.StraceLogDir(instance_.PerInstanceLogPath(""));
85 process_monitor_properties.StraceCommands(config_.straced_host_executables());
86
87 for (auto& command_source : command_sources_) {
88 if (command_source->Enabled()) {
89 auto commands = CF_EXPECT(command_source->Commands());
90 for (auto& command : commands) {
91 process_monitor_properties.AddCommand(std::move(command));
92 }
93 }
94 }
95 const auto& channel_to_secure_env =
96 snapshot_control_files_->run_cvd_to_secure_env_fd;
97 ProcessMonitor process_monitor(std::move(process_monitor_properties),
98 channel_to_secure_env);
99
100 CF_EXPECT(process_monitor.StartAndMonitorProcesses());
101 device_status_ = DeviceStatus::kActive;
102
103 while (true) {
104 // TODO: use select to handle simultaneous connections.
105 auto client = SharedFD::Accept(*server_);
106 while (client->IsOpen()) {
107 auto launcher_action_with_info_result = ReadLauncherActionFromFd(client);
108 if (!launcher_action_with_info_result.ok()) {
109 LOG(ERROR) << "Reading launcher command from monitor failed: "
110 << launcher_action_with_info_result.error().FormatForEnv();
111 break;
112 }
113 auto launcher_action_opt = std::move(*launcher_action_with_info_result);
114 if (!launcher_action_opt.has_value()) {
115 // client disconnected
116 break;
117 }
118 auto launcher_action = *launcher_action_opt;
119 if (launcher_action.action != LauncherAction::kExtended) {
120 HandleActionWithNoData(launcher_action.action, client, process_monitor);
121 continue;
122 }
123 auto result = HandleExtended(launcher_action, process_monitor);
124 auto response = LauncherResponse::kSuccess;
125 if (!result.ok()) {
126 LOG(ERROR) << "Failed to handle extended action request.";
127 LOG(ERROR) << result.error().FormatForEnv();
128 response = LauncherResponse::kError;
129 }
130 const auto n_written = client->Write(&response, sizeof(response));
131 if (n_written != sizeof(response)) {
132 LOG(ERROR) << "Failed to write response";
133 }
134 // extended operations for now are 1 time request-response exchanges.
135 // thus, we will close the client FD.
136 client->Close();
137 }
138 }
139 }
140
ResultSetup()141 Result<void> ServerLoopImpl::ResultSetup() {
142 auto launcher_monitor_path = instance_.launcher_monitor_socket_path();
143 server_ = SharedFD::SocketLocalServer(launcher_monitor_path.c_str(), false,
144 SOCK_STREAM, 0666);
145 CF_EXPECTF(server_->IsOpen(), "Error when opening launcher server: {}",
146 server_->StrError());
147 return {};
148 }
149
HandleExtended(const LauncherActionInfo & action_info,ProcessMonitor & process_monitor)150 Result<void> ServerLoopImpl::HandleExtended(
151 const LauncherActionInfo& action_info, ProcessMonitor& process_monitor) {
152 using ActionsCase =
153 ::cuttlefish::run_cvd::ExtendedLauncherAction::ActionsCase;
154
155 CF_EXPECT(action_info.action == LauncherAction::kExtended);
156 switch (action_info.extended_action.actions_case()) {
157 case ActionsCase::kSuspend: {
158 LOG(DEBUG) << "Run_cvd received suspend request.";
159 if (device_status_.load() == DeviceStatus::kActive) {
160 CF_EXPECT(HandleSuspend(process_monitor));
161 }
162 device_status_ = DeviceStatus::kSuspended;
163 return {};
164 }
165 case ActionsCase::kResume: {
166 LOG(DEBUG) << "Run_cvd received resume request.";
167 if (device_status_.load() == DeviceStatus::kSuspended) {
168 CF_EXPECT(HandleResume(process_monitor));
169 }
170 device_status_ = DeviceStatus::kActive;
171 return {};
172 }
173 case ActionsCase::kSnapshotTake: {
174 LOG(DEBUG) << "Run_cvd received snapshot request.";
175 CF_EXPECT(device_status_.load() == DeviceStatus::kSuspended,
176 "The device is not suspended, and snapshot cannot be taken");
177 CF_EXPECT(
178 HandleSnapshotTake(action_info.extended_action.snapshot_take()));
179 return {};
180 }
181 case ActionsCase::kStartScreenRecording: {
182 LOG(DEBUG) << "Run_cvd received start screen recording request.";
183 CF_EXPECT(HandleStartScreenRecording());
184 return {};
185 }
186 case ActionsCase::kStopScreenRecording: {
187 LOG(DEBUG) << "Run_cvd received stop screen recording request.";
188 CF_EXPECT(HandleStopScreenRecording());
189 return {};
190 }
191 case ActionsCase::kScreenshotDisplay: {
192 LOG(DEBUG) << "Run_cvd received screenshot display request.";
193 const auto& request = action_info.extended_action.screenshot_display();
194 CF_EXPECT(HandleScreenshotDisplay(request));
195 return {};
196 }
197 default:
198 return CF_ERR("Unsupported ExtendedLauncherAction");
199 }
200 }
201
HandleActionWithNoData(const LauncherAction action,const SharedFD & client,ProcessMonitor & process_monitor)202 void ServerLoopImpl::HandleActionWithNoData(const LauncherAction action,
203 const SharedFD& client,
204 ProcessMonitor& process_monitor) {
205 switch (action) {
206 case LauncherAction::kStop: {
207 auto stop = process_monitor.StopMonitoredProcesses();
208 if (stop.ok()) {
209 auto response = LauncherResponse::kSuccess;
210 client->Write(&response, sizeof(response));
211 std::exit(0);
212 } else {
213 LOG(ERROR) << "Failed to stop subprocesses:\n"
214 << stop.error().FormatForEnv();
215 auto response = LauncherResponse::kError;
216 client->Write(&response, sizeof(response));
217 }
218 break;
219 }
220 case LauncherAction::kFail: {
221 auto stop = process_monitor.StopMonitoredProcesses();
222 if (stop.ok()) {
223 auto response = LauncherResponse::kSuccess;
224 client->Write(&response, sizeof(response));
225 std::exit(RunnerExitCodes::kVirtualDeviceBootFailed);
226 } else {
227 auto response = LauncherResponse::kError;
228 client->Write(&response, sizeof(response));
229 LOG(ERROR) << "Failed to stop subprocesses:\n"
230 << stop.error().FormatForEnv();
231 }
232 break;
233 }
234 case LauncherAction::kStatus: {
235 // TODO(schuffelen): Return more information on a side channel
236 auto response = LauncherResponse::kSuccess;
237 client->Write(&response, sizeof(response));
238 break;
239 }
240 case LauncherAction::kPowerwash: {
241 LOG(INFO) << "Received a Powerwash request from the monitor socket";
242 const auto& disks = instance_.virtual_disk_paths();
243 auto overlay = instance_.PerInstancePath("overlay.img");
244 if (std::find(disks.begin(), disks.end(), overlay) == disks.end()) {
245 LOG(ERROR) << "Powerwash unsupported with --use_overlay=false";
246 auto response = LauncherResponse::kError;
247 client->Write(&response, sizeof(response));
248 break;
249 }
250
251 auto stop = process_monitor.StopMonitoredProcesses();
252 if (!stop.ok()) {
253 LOG(ERROR) << "Stopping processes failed:\n"
254 << stop.error().FormatForEnv();
255 auto response = LauncherResponse::kError;
256 client->Write(&response, sizeof(response));
257 break;
258 }
259 if (!PowerwashFiles()) {
260 LOG(ERROR) << "Powerwashing files failed.";
261 auto response = LauncherResponse::kError;
262 client->Write(&response, sizeof(response));
263 break;
264 }
265 auto response = LauncherResponse::kSuccess;
266 client->Write(&response, sizeof(response));
267
268 RestartRunCvd(client->UNMANAGED_Dup());
269 // RestartRunCvd should not return, so something went wrong.
270 response = LauncherResponse::kError;
271 client->Write(&response, sizeof(response));
272 LOG(FATAL) << "run_cvd in a bad state";
273 break;
274 }
275 case LauncherAction::kRestart: {
276 auto stop = process_monitor.StopMonitoredProcesses();
277 if (!stop.ok()) {
278 LOG(ERROR) << "Stopping processes failed:\n"
279 << stop.error().FormatForEnv();
280 auto response = LauncherResponse::kError;
281 client->Write(&response, sizeof(response));
282 break;
283 }
284 DeleteFifos();
285
286 auto response = LauncherResponse::kSuccess;
287 client->Write(&response, sizeof(response));
288 RestartRunCvd(client->UNMANAGED_Dup());
289 // RestartRunCvd should not return, so something went wrong.
290 response = LauncherResponse::kError;
291 client->Write(&response, sizeof(response));
292 LOG(FATAL) << "run_cvd in a bad state";
293 break;
294 }
295 default:
296 LOG(ERROR) << "Unrecognized launcher action: "
297 << static_cast<char>(action);
298 auto response = LauncherResponse::kError;
299 client->Write(&response, sizeof(response));
300 break;
301 }
302 }
303
DeleteFifos()304 void ServerLoopImpl::DeleteFifos() {
305 // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
306 std::vector<std::string> pipes = {
307 instance_.kernel_log_pipe_name(),
308 instance_.console_in_pipe_name(),
309 instance_.console_out_pipe_name(),
310 instance_.logcat_pipe_name(),
311 instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"),
312 instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
313 instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
314 instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
315 instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
316 instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
317 instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
318 instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
319 instance_.PerInstanceInternalPath("bt_fifo_vm.in"),
320 instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
321 instance_.PerInstanceInternalPath("nfc_fifo_vm.in"),
322 instance_.PerInstanceInternalPath("nfc_fifo_vm.out"),
323 instance_.PerInstanceInternalPath("uwb_fifo_vm.in"),
324 instance_.PerInstanceInternalPath("uwb_fifo_vm.out"),
325 instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
326 instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
327 instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
328 instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
329 instance_.PerInstanceInternalPath("confui_fifo_vm.in"),
330 instance_.PerInstanceInternalPath("confui_fifo_vm.out"),
331 instance_.PerInstanceInternalPath("sensors_fifo_vm.in"),
332 instance_.PerInstanceInternalPath("sensors_fifo_vm.out"),
333 };
334 for (const auto& pipe : pipes) {
335 unlink(pipe.c_str());
336 }
337 }
338
PowerwashFiles()339 bool ServerLoopImpl::PowerwashFiles() {
340 DeleteFifos();
341
342 // TODO(b/269669405): Figure out why this file is not being deleted
343 unlink(instance_.CrosvmSocketPath().c_str());
344 unlink(instance_.OpenwrtCrosvmSocketPath().c_str());
345
346 // TODO(schuffelen): Clean up duplication with assemble_cvd
347 unlink(instance_.PerInstancePath("NVChip").c_str());
348
349 auto kregistry_path = instance_.access_kregistry_path();
350 unlink(kregistry_path.c_str());
351 CreateBlankImage(kregistry_path, 2 /* mb */, "none");
352
353 auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
354 unlink(hwcomposer_pmem_path.c_str());
355 CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
356
357 auto pstore_path = instance_.pstore_path();
358 unlink(pstore_path.c_str());
359 CreateBlankImage(pstore_path, 2 /* mb */, "none");
360
361 auto sdcard_path = instance_.sdcard_path();
362 auto sdcard_size = FileSize(sdcard_path);
363 unlink(sdcard_path.c_str());
364 // round up
365 auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
366 LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
367 CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
368
369 struct OverlayFile {
370 std::string name;
371 std::string composite_disk_path;
372
373 OverlayFile(std::string name, std::string composite_disk_path)
374 : name(std::move(name)),
375 composite_disk_path(std::move(composite_disk_path)) {}
376 };
377 std::vector<OverlayFile> overlay_files{
378 OverlayFile("overlay.img", instance_.os_composite_disk_path())};
379 if (instance_.ap_boot_flow() !=
380 CuttlefishConfig::InstanceSpecific::APBootFlow::None) {
381 overlay_files.emplace_back(
382 OverlayFile("ap_overlay.img", instance_.ap_composite_disk_path()));
383 }
384 for (const auto& overlay_file : overlay_files) {
385 auto overlay_path = instance_.PerInstancePath(overlay_file.name.c_str());
386 auto composite_disk_path = overlay_file.composite_disk_path.c_str();
387
388 unlink(overlay_path.c_str());
389 if (!CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path,
390 overlay_path)) {
391 LOG(ERROR) << "CreateQcowOverlay failed";
392 return false;
393 }
394 }
395 return true;
396 }
397
RestartRunCvd(int notification_fd)398 void ServerLoopImpl::RestartRunCvd(int notification_fd) {
399 // On device creation, if the file "restore" exists, a restore of the device
400 // occurs. This means a restart will instead perform a restore, which is
401 // undesired behavior. Always try to delete the file "restore" if a restart is
402 // requested.
403 if (IsRestoring(config_)) {
404 CHECK(RemoveFile(config_.AssemblyPath("restore")));
405 }
406 auto config_path = config_.AssemblyPath("cuttlefish_config.json");
407 auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
408 WriteAll(followup_stdin, config_path + "\n");
409 followup_stdin->LSeek(0, SEEK_SET);
410 followup_stdin->UNMANAGED_Dup2(0);
411
412 auto argv_vec = gflags::GetArgvs();
413 std::unique_ptr<char*[]> argv(new char*[argv_vec.size() + 2]);
414 for (size_t i = 0; i < argv_vec.size(); i++) {
415 argv[i] = argv_vec[i].data();
416 }
417 // Will take precedence over any earlier arguments.
418 std::string reboot_notification =
419 "-reboot_notification_fd=" + std::to_string(notification_fd);
420 argv[argv_vec.size()] = reboot_notification.data();
421 argv[argv_vec.size() + 1] = nullptr;
422
423 execv("/proc/self/exe", argv.get());
424 // execve should not return, so something went wrong.
425 PLOG(ERROR) << "execv returned: ";
426 }
427
VmControlSocket() const428 Result<std::string> ServerLoopImpl::VmControlSocket() const {
429 CF_EXPECT_EQ(config_.vm_manager(), VmmMode::kCrosvm,
430 "Other VMs but crosvm is not yet supported.");
431 return instance_.CrosvmSocketPath();
432 }
433
434 } // namespace run_cvd_impl
435 } // namespace cuttlefish
436