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