1 //
2 // Copyright (C) 2019 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 #include "host/commands/run_cvd/launch.h"
17
18 #include <android-base/logging.h>
19 #include <utility>
20
21 #include "common/libs/fs/shared_fd.h"
22 #include "common/libs/utils/files.h"
23 #include "common/libs/utils/subprocess.h"
24 #include "host/commands/run_cvd/process_monitor.h"
25 #include "host/commands/run_cvd/runner_defs.h"
26 #include "host/libs/config/cuttlefish_config.h"
27 #include "host/libs/config/known_paths.h"
28
29 namespace cuttlefish {
30
31 namespace {
32
33 template <typename T>
single_element_emplace(T && element)34 std::vector<T> single_element_emplace(T&& element) {
35 std::vector<T> vec;
36 vec.emplace_back(std::move(element));
37 return vec;
38 }
39
40 } // namespace
41
LaunchKernelLogMonitor(const CuttlefishConfig & config,unsigned int number_of_event_pipes)42 KernelLogMonitorData LaunchKernelLogMonitor(
43 const CuttlefishConfig& config, unsigned int number_of_event_pipes) {
44 auto instance = config.ForDefaultInstance();
45 auto log_name = instance.kernel_log_pipe_name();
46 if (mkfifo(log_name.c_str(), 0600) != 0) {
47 LOG(ERROR) << "Unable to create named pipe at " << log_name << ": "
48 << strerror(errno);
49 return {};
50 }
51
52 SharedFD pipe;
53 // Open the pipe here (from the launcher) to ensure the pipe is not deleted
54 // due to the usage counters in the kernel reaching zero. If this is not done
55 // and the kernel_log_monitor crashes for some reason the VMM may get SIGPIPE.
56 pipe = SharedFD::Open(log_name.c_str(), O_RDWR);
57 Command command(KernelLogMonitorBinary());
58 command.AddParameter("-log_pipe_fd=", pipe);
59
60 KernelLogMonitorData ret;
61
62 if (number_of_event_pipes > 0) {
63 command.AddParameter("-subscriber_fds=");
64 for (unsigned int i = 0; i < number_of_event_pipes; ++i) {
65 SharedFD event_pipe_write_end, event_pipe_read_end;
66 if (!SharedFD::Pipe(&event_pipe_read_end, &event_pipe_write_end)) {
67 LOG(ERROR) << "Unable to create kernel log events pipe: " << strerror(errno);
68 std::exit(RunnerExitCodes::kPipeIOError);
69 }
70 if (i > 0) {
71 command.AppendToLastParameter(",");
72 }
73 command.AppendToLastParameter(event_pipe_write_end);
74 ret.pipes.push_back(event_pipe_read_end);
75 }
76 }
77
78 ret.commands.emplace_back(std::move(command));
79
80 return ret;
81 }
82
LaunchRootCanal(const CuttlefishConfig & config)83 std::vector<Command> LaunchRootCanal(const CuttlefishConfig& config) {
84 if (!config.enable_host_bluetooth()) {
85 return {};
86 }
87
88 auto instance = config.ForDefaultInstance();
89 Command command(RootCanalBinary());
90
91 // Test port
92 command.AddParameter(instance.rootcanal_test_port());
93 // HCI server port
94 command.AddParameter(instance.rootcanal_hci_port());
95 // Link server port
96 command.AddParameter(instance.rootcanal_link_port());
97 // Bluetooth controller properties file
98 command.AddParameter("--controller_properties_file=",
99 instance.rootcanal_config_file());
100 // Default commands file
101 command.AddParameter("--default_commands_file=",
102 instance.rootcanal_default_commands_file());
103
104 return single_element_emplace(std::move(command));
105 }
106
LaunchLogcatReceiver(const CuttlefishConfig & config)107 std::vector<Command> LaunchLogcatReceiver(const CuttlefishConfig& config) {
108 auto instance = config.ForDefaultInstance();
109 auto log_name = instance.logcat_pipe_name();
110 if (mkfifo(log_name.c_str(), 0600) != 0) {
111 LOG(ERROR) << "Unable to create named pipe at " << log_name << ": "
112 << strerror(errno);
113 return {};
114 }
115
116 SharedFD pipe;
117 // Open the pipe here (from the launcher) to ensure the pipe is not deleted
118 // due to the usage counters in the kernel reaching zero. If this is not done
119 // and the logcat_receiver crashes for some reason the VMM may get SIGPIPE.
120 pipe = SharedFD::Open(log_name.c_str(), O_RDWR);
121 Command command(LogcatReceiverBinary());
122 command.AddParameter("-log_pipe_fd=", pipe);
123
124 return single_element_emplace(std::move(command));
125 }
126
LaunchConfigServer(const CuttlefishConfig & config)127 std::vector<Command> LaunchConfigServer(const CuttlefishConfig& config) {
128 auto instance = config.ForDefaultInstance();
129 auto port = instance.config_server_port();
130 auto socket = SharedFD::VsockServer(port, SOCK_STREAM);
131 if (!socket->IsOpen()) {
132 LOG(ERROR) << "Unable to create configuration server socket: "
133 << socket->StrError();
134 std::exit(RunnerExitCodes::kConfigServerError);
135 }
136 Command cmd(ConfigServerBinary());
137 cmd.AddParameter("-server_fd=", socket);
138 return single_element_emplace(std::move(cmd));
139 }
140
LaunchTombstoneReceiver(const CuttlefishConfig & config)141 std::vector<Command> LaunchTombstoneReceiver(const CuttlefishConfig& config) {
142 auto instance = config.ForDefaultInstance();
143
144 std::string tombstoneDir = instance.PerInstancePath("tombstones");
145 if (!DirectoryExists(tombstoneDir.c_str())) {
146 LOG(DEBUG) << "Setting up " << tombstoneDir;
147 if (mkdir(tombstoneDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) <
148 0) {
149 LOG(ERROR) << "Failed to create tombstone directory: " << tombstoneDir
150 << ". Error: " << errno;
151 exit(RunnerExitCodes::kTombstoneDirCreationError);
152 return {};
153 }
154 }
155
156 auto port = instance.tombstone_receiver_port();
157 auto socket = SharedFD::VsockServer(port, SOCK_STREAM);
158 if (!socket->IsOpen()) {
159 LOG(ERROR) << "Unable to create tombstone server socket: "
160 << socket->StrError();
161 std::exit(RunnerExitCodes::kTombstoneServerError);
162 return {};
163 }
164 Command cmd(TombstoneReceiverBinary());
165 cmd.AddParameter("-server_fd=", socket);
166 cmd.AddParameter("-tombstone_dir=", tombstoneDir);
167
168 return single_element_emplace(std::move(cmd));
169 }
170
LaunchMetrics()171 std::vector<Command> LaunchMetrics() {
172 return single_element_emplace(Command(MetricsBinary()));
173 }
174
LaunchGnssGrpcProxyServerIfEnabled(const CuttlefishConfig & config)175 std::vector<Command> LaunchGnssGrpcProxyServerIfEnabled(
176 const CuttlefishConfig& config) {
177 if (!config.enable_gnss_grpc_proxy() || !FileExists(GnssGrpcProxyBinary())) {
178 return {};
179 }
180
181 Command gnss_grpc_proxy_cmd(GnssGrpcProxyBinary());
182 auto instance = config.ForDefaultInstance();
183
184 auto gnss_in_pipe_name = instance.gnss_in_pipe_name();
185 if (mkfifo(gnss_in_pipe_name.c_str(), 0600) != 0) {
186 auto error = errno;
187 LOG(ERROR) << "Failed to create gnss input fifo for crosvm: "
188 << strerror(error);
189 return {};
190 }
191
192 auto gnss_out_pipe_name = instance.gnss_out_pipe_name();
193 if (mkfifo(gnss_out_pipe_name.c_str(), 0660) != 0) {
194 auto error = errno;
195 LOG(ERROR) << "Failed to create gnss output fifo for crosvm: "
196 << strerror(error);
197 return {};
198 }
199
200 // These fds will only be read from or written to, but open them with
201 // read and write access to keep them open in case the subprocesses exit
202 SharedFD gnss_grpc_proxy_in_wr =
203 SharedFD::Open(gnss_in_pipe_name.c_str(), O_RDWR);
204 if (!gnss_grpc_proxy_in_wr->IsOpen()) {
205 LOG(ERROR) << "Failed to open gnss_grpc_proxy input fifo for writes: "
206 << gnss_grpc_proxy_in_wr->StrError();
207 return {};
208 }
209
210 SharedFD gnss_grpc_proxy_out_rd =
211 SharedFD::Open(gnss_out_pipe_name.c_str(), O_RDWR);
212 if (!gnss_grpc_proxy_out_rd->IsOpen()) {
213 LOG(ERROR) << "Failed to open gnss_grpc_proxy output fifo for reads: "
214 << gnss_grpc_proxy_out_rd->StrError();
215 return {};
216 }
217
218 const unsigned gnss_grpc_proxy_server_port =
219 instance.gnss_grpc_proxy_server_port();
220 gnss_grpc_proxy_cmd.AddParameter("--gnss_in_fd=", gnss_grpc_proxy_in_wr);
221 gnss_grpc_proxy_cmd.AddParameter("--gnss_out_fd=", gnss_grpc_proxy_out_rd);
222 gnss_grpc_proxy_cmd.AddParameter("--gnss_grpc_port=",
223 gnss_grpc_proxy_server_port);
224 if (!instance.gnss_file_path().empty()) {
225 // If path is provided, proxy will start as local mode.
226 gnss_grpc_proxy_cmd.AddParameter("--gnss_file_path=",
227 instance.gnss_file_path());
228 }
229 return single_element_emplace(std::move(gnss_grpc_proxy_cmd));
230 }
231
LaunchBluetoothConnector(const CuttlefishConfig & config)232 std::vector<Command> LaunchBluetoothConnector(const CuttlefishConfig& config) {
233 auto instance = config.ForDefaultInstance();
234 std::vector<std::string> fifo_paths = {
235 instance.PerInstanceInternalPath("bt_fifo_vm.in"),
236 instance.PerInstanceInternalPath("bt_fifo_vm.out"),
237 };
238 std::vector<SharedFD> fifos;
239 for (const auto& path : fifo_paths) {
240 unlink(path.c_str());
241 if (mkfifo(path.c_str(), 0660) < 0) {
242 PLOG(ERROR) << "Could not create " << path;
243 return {};
244 }
245 auto fd = SharedFD::Open(path, O_RDWR);
246 if (!fd->IsOpen()) {
247 LOG(ERROR) << "Could not open " << path << ": " << fd->StrError();
248 return {};
249 }
250 fifos.push_back(fd);
251 }
252
253 Command command(DefaultHostArtifactsPath("bin/bt_connector"));
254 command.AddParameter("-bt_out=", fifos[0]);
255 command.AddParameter("-bt_in=", fifos[1]);
256 command.AddParameter("-hci_port=", instance.rootcanal_hci_port());
257 command.AddParameter("-link_port=", instance.rootcanal_link_port());
258 command.AddParameter("-test_port=", instance.rootcanal_test_port());
259 return single_element_emplace(std::move(command));
260 }
261
LaunchSecureEnvironment(const CuttlefishConfig & config)262 std::vector<Command> LaunchSecureEnvironment(const CuttlefishConfig& config) {
263 auto instance = config.ForDefaultInstance();
264 std::vector<std::string> fifo_paths = {
265 instance.PerInstanceInternalPath("keymaster_fifo_vm.in"),
266 instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
267 instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
268 instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
269 };
270 std::vector<SharedFD> fifos;
271 for (const auto& path : fifo_paths) {
272 unlink(path.c_str());
273 if (mkfifo(path.c_str(), 0600) < 0) {
274 PLOG(ERROR) << "Could not create " << path;
275 return {};
276 }
277 auto fd = SharedFD::Open(path, O_RDWR);
278 if (!fd->IsOpen()) {
279 LOG(ERROR) << "Could not open " << path << ": " << fd->StrError();
280 return {};
281 }
282 fifos.push_back(fd);
283 }
284
285 Command command(HostBinaryPath("secure_env"));
286 command.AddParameter("-keymaster_fd_out=", fifos[0]);
287 command.AddParameter("-keymaster_fd_in=", fifos[1]);
288 command.AddParameter("-gatekeeper_fd_out=", fifos[2]);
289 command.AddParameter("-gatekeeper_fd_in=", fifos[3]);
290
291 const auto& secure_hals = config.secure_hals();
292 bool secure_keymint = secure_hals.count(SecureHal::Keymint) > 0;
293 command.AddParameter("-keymint_impl=", secure_keymint ? "tpm" : "software");
294 bool secure_gatekeeper = secure_hals.count(SecureHal::Gatekeeper) > 0;
295 auto gatekeeper_impl = secure_gatekeeper ? "tpm" : "software";
296 command.AddParameter("-gatekeeper_impl=", gatekeeper_impl);
297
298 return single_element_emplace(std::move(command));
299 }
300
LaunchVehicleHalServerIfEnabled(const CuttlefishConfig & config)301 std::vector<Command> LaunchVehicleHalServerIfEnabled(
302 const CuttlefishConfig& config) {
303 if (!config.enable_vehicle_hal_grpc_server() ||
304 !FileExists(config.vehicle_hal_grpc_server_binary())) {
305 return {};
306 }
307
308 Command grpc_server(config.vehicle_hal_grpc_server_binary());
309 auto instance = config.ForDefaultInstance();
310
311 const unsigned vhal_server_cid = 2;
312 const unsigned vhal_server_port = instance.vehicle_hal_server_port();
313 const std::string vhal_server_power_state_file =
314 AbsolutePath(instance.PerInstancePath("power_state"));
315 const std::string vhal_server_power_state_socket =
316 AbsolutePath(instance.PerInstancePath("power_state_socket"));
317
318 grpc_server.AddParameter("--server_cid=", vhal_server_cid);
319 grpc_server.AddParameter("--server_port=", vhal_server_port);
320 grpc_server.AddParameter("--power_state_file=", vhal_server_power_state_file);
321 grpc_server.AddParameter("--power_state_socket=", vhal_server_power_state_socket);
322 return single_element_emplace(std::move(grpc_server));
323 }
324
LaunchConsoleForwarderIfEnabled(const CuttlefishConfig & config)325 std::vector<Command> LaunchConsoleForwarderIfEnabled(
326 const CuttlefishConfig& config) {
327 if (!config.console()) {
328 return {};
329 }
330
331 Command console_forwarder_cmd(ConsoleForwarderBinary());
332 auto instance = config.ForDefaultInstance();
333
334 auto console_in_pipe_name = instance.console_in_pipe_name();
335 if (mkfifo(console_in_pipe_name.c_str(), 0600) != 0) {
336 auto error = errno;
337 LOG(ERROR) << "Failed to create console input fifo for crosvm: "
338 << strerror(error);
339 return {};
340 }
341
342 auto console_out_pipe_name = instance.console_out_pipe_name();
343 if (mkfifo(console_out_pipe_name.c_str(), 0660) != 0) {
344 auto error = errno;
345 LOG(ERROR) << "Failed to create console output fifo for crosvm: "
346 << strerror(error);
347 return {};
348 }
349
350 // These fds will only be read from or written to, but open them with
351 // read and write access to keep them open in case the subprocesses exit
352 SharedFD console_forwarder_in_wr =
353 SharedFD::Open(console_in_pipe_name.c_str(), O_RDWR);
354 if (!console_forwarder_in_wr->IsOpen()) {
355 LOG(ERROR) << "Failed to open console_forwarder input fifo for writes: "
356 << console_forwarder_in_wr->StrError();
357 return {};
358 }
359
360 SharedFD console_forwarder_out_rd =
361 SharedFD::Open(console_out_pipe_name.c_str(), O_RDWR);
362 if (!console_forwarder_out_rd->IsOpen()) {
363 LOG(ERROR) << "Failed to open console_forwarder output fifo for reads: "
364 << console_forwarder_out_rd->StrError();
365 return {};
366 }
367
368 console_forwarder_cmd.AddParameter("--console_in_fd=", console_forwarder_in_wr);
369 console_forwarder_cmd.AddParameter("--console_out_fd=", console_forwarder_out_rd);
370 return single_element_emplace(std::move(console_forwarder_cmd));
371 }
372
373 } // namespace cuttlefish
374