• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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