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