• 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 <gflags/gflags.h>
20 #include <unistd.h>
21 #include <string>
22 
23 #include "common/libs/fs/shared_buf.h"
24 #include "common/libs/utils/files.h"
25 #include "common/libs/utils/subprocess.h"
26 #include "host/commands/run_cvd/runner_defs.h"
27 #include "host/libs/config/cuttlefish_config.h"
28 #include "host/libs/config/data_image.h"
29 
30 namespace cuttlefish {
31 
32 namespace {
33 
CreateQcowOverlay(const std::string & crosvm_path,const std::string & backing_file,const std::string & output_overlay_path)34 bool CreateQcowOverlay(const std::string& crosvm_path,
35                        const std::string& backing_file,
36                        const std::string& output_overlay_path) {
37   Command crosvm_qcow2_cmd(crosvm_path);
38   crosvm_qcow2_cmd.AddParameter("create_qcow2");
39   crosvm_qcow2_cmd.AddParameter("--backing_file=", backing_file);
40   crosvm_qcow2_cmd.AddParameter(output_overlay_path);
41   int success = crosvm_qcow2_cmd.Start().Wait();
42   if (success != 0) {
43     LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
44                << success;
45     return false;
46   }
47   return true;
48 }
49 
DeleteFifos(const CuttlefishConfig::InstanceSpecific & instance)50 void DeleteFifos(const CuttlefishConfig::InstanceSpecific& instance) {
51   // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
52   std::vector<std::string> pipes = {
53       instance.kernel_log_pipe_name(),
54       instance.console_in_pipe_name(),
55       instance.console_out_pipe_name(),
56       instance.logcat_pipe_name(),
57       instance.PerInstanceInternalPath("keymaster_fifo_vm.in"),
58       instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
59       instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
60       instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
61       instance.PerInstanceInternalPath("bt_fifo_vm.in"),
62       instance.PerInstanceInternalPath("bt_fifo_vm.out"),
63   };
64   for (const auto& pipe : pipes) {
65     unlink(pipe.c_str());
66   }
67 }
68 
PowerwashFiles()69 bool PowerwashFiles() {
70   auto config = CuttlefishConfig::Get();
71   if (!config) {
72     LOG(ERROR) << "Could not load the config.";
73     return false;
74   }
75   auto instance = config->ForDefaultInstance();
76 
77   DeleteFifos(instance);
78 
79   // TODO(schuffelen): Clean up duplication with assemble_cvd
80   auto kregistry_path = instance.access_kregistry_path();
81   unlink(kregistry_path.c_str());
82   CreateBlankImage(kregistry_path, 2 /* mb */, "none");
83 
84   auto pstore_path = instance.pstore_path();
85   unlink(pstore_path.c_str());
86   CreateBlankImage(pstore_path, 2 /* mb */, "none");
87 
88   auto sdcard_path = instance.sdcard_path();
89   auto sdcard_size = FileSize(sdcard_path);
90   unlink(sdcard_path.c_str());
91   // round up
92   auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
93   LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
94   CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
95 
96   auto overlay_path = instance.PerInstancePath("overlay.img");
97   unlink(overlay_path.c_str());
98   if (!CreateQcowOverlay(config->crosvm_binary(),
99                          instance.os_composite_disk_path(), overlay_path)) {
100     LOG(ERROR) << "CreateQcowOverlay failed";
101     return false;
102   }
103   return true;
104 }
105 
RestartRunCvd(const CuttlefishConfig & config,int notification_fd)106 void RestartRunCvd(const CuttlefishConfig& config, int notification_fd) {
107   auto config_path = config.AssemblyPath("cuttlefish_config.json");
108   auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
109   WriteAll(followup_stdin, config_path + "\n");
110   followup_stdin->LSeek(0, SEEK_SET);
111   followup_stdin->UNMANAGED_Dup2(0);
112 
113   auto argv_vec = gflags::GetArgvs();
114   char** argv = new char*[argv_vec.size() + 2];
115   for (size_t i = 0; i < argv_vec.size(); i++) {
116     argv[i] = argv_vec[i].data();
117   }
118   // Will take precedence over any earlier arguments.
119   std::string reboot_notification =
120       "-reboot_notification_fd=" + std::to_string(notification_fd);
121   argv[argv_vec.size()] = reboot_notification.data();
122   argv[argv_vec.size() + 1] = nullptr;
123 
124   execv("/proc/self/exe", argv);
125   // execve should not return, so something went wrong.
126   PLOG(ERROR) << "execv returned: ";
127 }
128 
129 }  // namespace
130 
ServerLoop(SharedFD server,ProcessMonitor * process_monitor)131 void ServerLoop(SharedFD server, ProcessMonitor* process_monitor) {
132   while (true) {
133     // TODO: use select to handle simultaneous connections.
134     auto client = SharedFD::Accept(*server);
135     LauncherAction action;
136     while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) {
137       switch (action) {
138         case LauncherAction::kStop:
139           if (process_monitor->StopMonitoredProcesses()) {
140             auto response = LauncherResponse::kSuccess;
141             client->Write(&response, sizeof(response));
142             std::exit(0);
143           } else {
144             auto response = LauncherResponse::kError;
145             client->Write(&response, sizeof(response));
146           }
147           break;
148         case LauncherAction::kStatus: {
149           // TODO(schuffelen): Return more information on a side channel
150           auto response = LauncherResponse::kSuccess;
151           client->Write(&response, sizeof(response));
152           break;
153         }
154         case LauncherAction::kPowerwash: {
155           LOG(INFO) << "Received a Powerwash request from the monitor socket";
156           if (!process_monitor->StopMonitoredProcesses()) {
157             LOG(ERROR) << "Stopping processes failed.";
158             auto response = LauncherResponse::kError;
159             client->Write(&response, sizeof(response));
160             break;
161           }
162           if (!PowerwashFiles()) {
163             LOG(ERROR) << "Powerwashing files failed.";
164             auto response = LauncherResponse::kError;
165             client->Write(&response, sizeof(response));
166             break;
167           }
168           auto response = LauncherResponse::kSuccess;
169           client->Write(&response, sizeof(response));
170 
171           auto config = CuttlefishConfig::Get();
172           CHECK(config) << "Could not load config";
173           RestartRunCvd(*config, client->UNMANAGED_Dup());
174           // RestartRunCvd should not return, so something went wrong.
175           response = LauncherResponse::kError;
176           client->Write(&response, sizeof(response));
177           LOG(FATAL) << "run_cvd in a bad state";
178           break;
179         }
180         case LauncherAction::kRestart: {
181           if (!process_monitor->StopMonitoredProcesses()) {
182             LOG(ERROR) << "Stopping processes failed.";
183             auto response = LauncherResponse::kError;
184             client->Write(&response, sizeof(response));
185             break;
186           }
187 
188           auto config = CuttlefishConfig::Get();
189           CHECK(config) << "Could not load config";
190           auto instance = config->ForDefaultInstance();
191           DeleteFifos(instance);
192 
193           auto response = LauncherResponse::kSuccess;
194           client->Write(&response, sizeof(response));
195           CHECK(config) << "Could not load config";
196           RestartRunCvd(*config, client->UNMANAGED_Dup());
197           // RestartRunCvd should not return, so something went wrong.
198           response = LauncherResponse::kError;
199           client->Write(&response, sizeof(response));
200           LOG(FATAL) << "run_cvd in a bad state";
201           break;
202         }
203         default:
204           LOG(ERROR) << "Unrecognized launcher action: "
205                      << static_cast<char>(action);
206           auto response = LauncherResponse::kError;
207           client->Write(&response, sizeof(response));
208       }
209     }
210   }
211 }
212 
213 }  // namespace cuttlefish
214