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