Greg Hartman | 86b114a | 2017-11-03 21:04:14 -0700 | [diff] [blame] | 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 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 17 | #include <limits.h> |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 18 | #include <signal.h> |
Greg Hartman | 610c03f | 2017-10-31 17:44:11 -0700 | [diff] [blame] | 19 | #include <stdio.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 20 | #include <stdlib.h> |
Greg Hartman | 13ee8b3 | 2017-11-13 21:09:15 -0800 | [diff] [blame] | 21 | #include <sys/types.h> |
| 22 | #include <sys/stat.h> |
| 23 | #include <sys/wait.h> |
Greg Hartman | 6abdbb9 | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 24 | #include <fcntl.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 25 | #include <unistd.h> |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 26 | |
Ryan Haining | b48ceaf | 2018-03-27 20:13:59 -0700 | [diff] [blame] | 27 | #include <algorithm> |
Jorge E. Moreira | 3d838dc | 2018-07-10 11:49:38 -0700 | [diff] [blame] | 28 | #include <functional> |
Jorge E. Moreira | 5020a66 | 2018-07-09 17:07:14 -0700 | [diff] [blame] | 29 | #include <iostream> |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 30 | #include <fstream> |
Greg Hartman | 5587b28 | 2017-11-11 12:01:45 -0800 | [diff] [blame] | 31 | #include <iomanip> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 32 | #include <memory> |
Tomasz Wiszkowski | 64446de | 2017-08-15 15:40:37 -0700 | [diff] [blame] | 33 | #include <sstream> |
Ryan Haining | b48ceaf | 2018-03-27 20:13:59 -0700 | [diff] [blame] | 34 | #include <string> |
Jorge E. Moreira | b5a71d7 | 2018-07-22 23:01:20 -0700 | [diff] [blame] | 35 | #include <thread> |
Ryan Haining | b48ceaf | 2018-03-27 20:13:59 -0700 | [diff] [blame] | 36 | #include <vector> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 37 | |
Cody Schuffelen | f4a1cdb | 2019-11-13 16:51:16 -0800 | [diff] [blame] | 38 | #include <android-base/strings.h> |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 39 | #include <gflags/gflags.h> |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 40 | #include <glog/logging.h> |
| 41 | |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 42 | #include "common/libs/fs/shared_buf.h" |
Greg Hartman | 6abdbb9 | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 43 | #include "common/libs/fs/shared_fd.h" |
Tomasz Wiszkowski | 525d02b | 2017-08-14 11:43:04 -0700 | [diff] [blame] | 44 | #include "common/libs/fs/shared_select.h" |
Jorge E. Moreira | 2a777f6 | 2018-06-13 17:28:10 -0700 | [diff] [blame] | 45 | #include "common/libs/utils/environment.h" |
Jorge E. Moreira | 02f464c | 2018-07-06 11:30:34 -0700 | [diff] [blame] | 46 | #include "common/libs/utils/files.h" |
Jorge E. Moreira | 6a9d629 | 2018-06-11 11:52:57 -0700 | [diff] [blame] | 47 | #include "common/libs/utils/subprocess.h" |
Jorge E. Moreira | 22561d9 | 2018-06-22 17:17:21 -0700 | [diff] [blame] | 48 | #include "common/libs/utils/size_utils.h" |
Cody Schuffelen | e46ae52 | 2019-12-05 12:55:45 -0800 | [diff] [blame] | 49 | #include "host/commands/run_cvd/kernel_args.h" |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 50 | #include "host/commands/run_cvd/launch.h" |
| 51 | #include "host/commands/run_cvd/runner_defs.h" |
| 52 | #include "host/commands/run_cvd/process_monitor.h" |
Jorge E. Moreira | 577383b | 2018-05-24 14:17:51 -0700 | [diff] [blame] | 53 | #include "host/libs/config/cuttlefish_config.h" |
Jorge E. Moreira | 66e9a1a | 2018-07-26 17:17:47 -0700 | [diff] [blame] | 54 | #include "host/commands/kernel_log_monitor/kernel_log_server.h" |
Jorge E. Moreira | 7123e2e | 2019-09-05 13:47:29 -0700 | [diff] [blame] | 55 | #include <host/libs/vm_manager/crosvm_manager.h> |
Jorge E. Moreira | a8142f9 | 2018-06-13 17:33:55 -0700 | [diff] [blame] | 56 | #include "host/libs/vm_manager/vm_manager.h" |
Jorge E. Moreira | 8832283 | 2018-07-22 16:41:01 -0700 | [diff] [blame] | 57 | #include "host/libs/vm_manager/qemu_manager.h" |
Tomasz Wiszkowski | bb6c162 | 2017-09-05 14:03:11 -0700 | [diff] [blame] | 58 | |
Greg Hartman | 36cc7c4 | 2017-11-13 18:05:01 -0800 | [diff] [blame] | 59 | using vsoc::GetPerInstanceDefault; |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 60 | using cvd::RunnerExitCodes; |
Greg Hartman | 36cc7c4 | 2017-11-13 18:05:01 -0800 | [diff] [blame] | 61 | |
Tomasz Wiszkowski | e99c411 | 2017-07-05 10:17:43 -0700 | [diff] [blame] | 62 | namespace { |
Ping-Hao Wu | fe9f69b | 2018-01-10 16:43:26 -0800 | [diff] [blame] | 63 | |
Cody Schuffelen | d12e0c9 | 2019-01-29 15:44:45 -0800 | [diff] [blame] | 64 | cvd::OnSocketReadyCb GetOnSubprocessExitCallback( |
| 65 | const vsoc::CuttlefishConfig& config) { |
| 66 | if (config.restart_subprocesses()) { |
| 67 | return cvd::ProcessMonitor::RestartOnExitCb; |
Jorge E. Moreira | 3d955ae | 2018-11-07 23:06:44 -0800 | [diff] [blame] | 68 | } else { |
Cody Schuffelen | d12e0c9 | 2019-01-29 15:44:45 -0800 | [diff] [blame] | 69 | return cvd::ProcessMonitor::DoNotMonitorCb; |
Jorge E. Moreira | 3d955ae | 2018-11-07 23:06:44 -0800 | [diff] [blame] | 70 | } |
| 71 | } |
| 72 | |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 73 | // Maintains the state of the boot process, once a final state is reached |
| 74 | // (success or failure) it sends the appropriate exit code to the foreground |
| 75 | // launcher process |
| 76 | class CvdBootStateMachine { |
| 77 | public: |
| 78 | CvdBootStateMachine(cvd::SharedFD fg_launcher_pipe) |
| 79 | : fg_launcher_pipe_(fg_launcher_pipe), state_(kBootStarted) {} |
| 80 | |
| 81 | // Returns true if the machine is left in a final state |
| 82 | bool OnBootEvtReceived(cvd::SharedFD boot_events_pipe) { |
| 83 | monitor::BootEvent evt; |
| 84 | auto bytes_read = boot_events_pipe->Read(&evt, sizeof(evt)); |
| 85 | if (bytes_read != sizeof(evt)) { |
| 86 | LOG(ERROR) << "Fail to read a complete event, read " << bytes_read |
| 87 | << " bytes only instead of the expected " << sizeof(evt); |
| 88 | state_ |= kGuestBootFailed; |
| 89 | } else if (evt == monitor::BootEvent::BootCompleted) { |
| 90 | LOG(INFO) << "Virtual device booted successfully"; |
| 91 | state_ |= kGuestBootCompleted; |
| 92 | } else if (evt == monitor::BootEvent::BootFailed) { |
| 93 | LOG(ERROR) << "Virtual device failed to boot"; |
| 94 | state_ |= kGuestBootFailed; |
| 95 | } // Ignore the other signals |
| 96 | |
| 97 | return MaybeWriteToForegroundLauncher(); |
| 98 | } |
| 99 | |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 100 | bool BootCompleted() const { |
Cody Schuffelen | e900837 | 2019-11-19 18:51:18 -0800 | [diff] [blame] | 101 | return state_ & kGuestBootCompleted; |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 102 | } |
| 103 | |
| 104 | bool BootFailed() const { |
Cody Schuffelen | e900837 | 2019-11-19 18:51:18 -0800 | [diff] [blame] | 105 | return state_ & kGuestBootFailed; |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | private: |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 109 | void SendExitCode(cvd::RunnerExitCodes exit_code) { |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 110 | fg_launcher_pipe_->Write(&exit_code, sizeof(exit_code)); |
| 111 | // The foreground process will exit after receiving the exit code, if we try |
| 112 | // to write again we'll get a SIGPIPE |
| 113 | fg_launcher_pipe_->Close(); |
| 114 | } |
| 115 | bool MaybeWriteToForegroundLauncher() { |
| 116 | if (fg_launcher_pipe_->IsOpen()) { |
| 117 | if (BootCompleted()) { |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 118 | SendExitCode(cvd::RunnerExitCodes::kSuccess); |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 119 | } else if (state_ & kGuestBootFailed) { |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 120 | SendExitCode(cvd::RunnerExitCodes::kVirtualDeviceBootFailed); |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 121 | } else { |
| 122 | // No final state was reached |
| 123 | return false; |
| 124 | } |
| 125 | } |
| 126 | // Either we sent the code before or just sent it, in any case the state is |
| 127 | // final |
| 128 | return true; |
| 129 | } |
| 130 | |
| 131 | cvd::SharedFD fg_launcher_pipe_; |
| 132 | int state_; |
| 133 | static const int kBootStarted = 0; |
| 134 | static const int kGuestBootCompleted = 1 << 0; |
| 135 | static const int kGuestBootFailed = 1 << 1; |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 136 | }; |
| 137 | |
| 138 | // Abuse the process monitor to make it call us back when boot events are ready |
| 139 | void SetUpHandlingOfBootEvents( |
| 140 | cvd::ProcessMonitor* process_monitor, cvd::SharedFD boot_events_pipe, |
| 141 | std::shared_ptr<CvdBootStateMachine> state_machine) { |
| 142 | process_monitor->MonitorExistingSubprocess( |
| 143 | // A dummy command, so logs are desciptive |
| 144 | cvd::Command("boot_events_listener"), |
| 145 | // A dummy subprocess, with the boot events pipe as control socket |
| 146 | cvd::Subprocess(-1, boot_events_pipe), |
| 147 | [boot_events_pipe, state_machine](cvd::MonitorEntry*) { |
| 148 | auto sent_code = state_machine->OnBootEvtReceived(boot_events_pipe); |
| 149 | return !sent_code; |
| 150 | }); |
| 151 | } |
| 152 | |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 153 | bool WriteCuttlefishEnvironment(const vsoc::CuttlefishConfig& config) { |
| 154 | auto env = cvd::SharedFD::Open(config.cuttlefish_env_path().c_str(), |
Greg Hartman | 6abdbb9 | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 155 | O_CREAT | O_RDWR, 0755); |
| 156 | if (!env->IsOpen()) { |
| 157 | LOG(ERROR) << "Unable to create cuttlefish.env file"; |
| 158 | return false; |
| 159 | } |
| 160 | std::string config_env = "export CUTTLEFISH_PER_INSTANCE_PATH=\"" + |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 161 | config.PerInstancePath(".") + "\"\n"; |
Cody Schuffelen | 3c35fd8 | 2019-12-11 18:39:46 -0800 | [diff] [blame^] | 162 | config_env += "export ANDROID_SERIAL=" + config.adb_ip_and_port() + "\n"; |
Greg Hartman | 6abdbb9 | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 163 | env->Write(config_env.c_str(), config_env.size()); |
| 164 | return true; |
| 165 | } |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 166 | |
| 167 | // Forks and returns the write end of a pipe to the child process. The parent |
| 168 | // process waits for boot events to come through the pipe and exits accordingly. |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 169 | cvd::SharedFD DaemonizeLauncher(const vsoc::CuttlefishConfig& config) { |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 170 | cvd::SharedFD read_end, write_end; |
| 171 | if (!cvd::SharedFD::Pipe(&read_end, &write_end)) { |
| 172 | LOG(ERROR) << "Unable to create pipe"; |
| 173 | return cvd::SharedFD(); // a closed FD |
| 174 | } |
| 175 | auto pid = fork(); |
| 176 | if (pid) { |
| 177 | // Explicitly close here, otherwise we may end up reading forever if the |
| 178 | // child process dies. |
| 179 | write_end->Close(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 180 | RunnerExitCodes exit_code; |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 181 | auto bytes_read = read_end->Read(&exit_code, sizeof(exit_code)); |
| 182 | if (bytes_read != sizeof(exit_code)) { |
| 183 | LOG(ERROR) << "Failed to read a complete exit code, read " << bytes_read |
| 184 | << " bytes only instead of the expected " << sizeof(exit_code); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 185 | exit_code = RunnerExitCodes::kPipeIOError; |
| 186 | } else if (exit_code == RunnerExitCodes::kSuccess) { |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 187 | LOG(INFO) << "Virtual device booted successfully"; |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 188 | } else if (exit_code == RunnerExitCodes::kVirtualDeviceBootFailed) { |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 189 | LOG(ERROR) << "Virtual device failed to boot"; |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 190 | } else { |
| 191 | LOG(ERROR) << "Unexpected exit code: " << exit_code; |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 192 | } |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 193 | if (exit_code == RunnerExitCodes::kSuccess) { |
Jorge E. Moreira | 8dad504 | 2019-10-01 16:04:52 -0700 | [diff] [blame] | 194 | LOG(INFO) << vsoc::kBootCompletedMessage; |
| 195 | } else { |
| 196 | LOG(INFO) << vsoc::kBootFailedMessage; |
| 197 | } |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 198 | std::exit(exit_code); |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 199 | } else { |
| 200 | // The child returns the write end of the pipe |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 201 | if (daemon(/*nochdir*/ 1, /*noclose*/ 1) != 0) { |
| 202 | LOG(ERROR) << "Failed to daemonize child process: " << strerror(errno); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 203 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 204 | } |
| 205 | // Redirect standard I/O |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 206 | auto log_path = config.launcher_log_path(); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 207 | auto log = |
| 208 | cvd::SharedFD::Open(log_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, |
| 209 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
| 210 | if (!log->IsOpen()) { |
| 211 | LOG(ERROR) << "Failed to create launcher log file: " << log->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 212 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 213 | } |
| 214 | auto dev_null = cvd::SharedFD::Open("/dev/null", O_RDONLY); |
| 215 | if (!dev_null->IsOpen()) { |
| 216 | LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 217 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 218 | } |
| 219 | if (dev_null->UNMANAGED_Dup2(0) < 0) { |
| 220 | LOG(ERROR) << "Failed dup2 stdin: " << dev_null->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 221 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 222 | } |
| 223 | if (log->UNMANAGED_Dup2(1) < 0) { |
| 224 | LOG(ERROR) << "Failed dup2 stdout: " << log->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 225 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 226 | } |
| 227 | if (log->UNMANAGED_Dup2(2) < 0) { |
| 228 | LOG(ERROR) << "Failed dup2 seterr: " << log->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 229 | std::exit(RunnerExitCodes::kDaemonizationError); |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 230 | } |
| 231 | |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 232 | read_end->Close(); |
| 233 | return write_end; |
| 234 | } |
| 235 | } |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 236 | |
Jorge E. Moreira | 077d300 | 2018-07-20 11:43:05 -0700 | [diff] [blame] | 237 | void ServerLoop(cvd::SharedFD server, |
Jorge E. Moreira | 2be306d | 2019-08-30 11:54:32 -0700 | [diff] [blame] | 238 | cvd::ProcessMonitor* process_monitor) { |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 239 | while (true) { |
| 240 | // TODO: use select to handle simultaneous connections. |
| 241 | auto client = cvd::SharedFD::Accept(*server); |
| 242 | cvd::LauncherAction action; |
Jorge E. Moreira | be7049a | 2018-07-26 18:12:13 -0700 | [diff] [blame] | 243 | while (client->IsOpen() && client->Read(&action, sizeof(action)) > 0) { |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 244 | switch (action) { |
| 245 | case cvd::LauncherAction::kStop: |
Jorge E. Moreira | 7123e2e | 2019-09-05 13:47:29 -0700 | [diff] [blame] | 246 | if (process_monitor->StopMonitoredProcesses()) { |
| 247 | auto response = cvd::LauncherResponse::kSuccess; |
| 248 | client->Write(&response, sizeof(response)); |
| 249 | std::exit(0); |
| 250 | } else { |
| 251 | auto response = cvd::LauncherResponse::kError; |
| 252 | client->Write(&response, sizeof(response)); |
| 253 | } |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 254 | break; |
Cody Schuffelen | 4f8e330 | 2019-10-23 11:21:10 -0700 | [diff] [blame] | 255 | case cvd::LauncherAction::kStatus: { |
| 256 | // TODO(schuffelen): Return more information on a side channel |
| 257 | auto response = cvd::LauncherResponse::kSuccess; |
| 258 | client->Write(&response, sizeof(response)); |
| 259 | break; |
| 260 | } |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 261 | default: |
| 262 | LOG(ERROR) << "Unrecognized launcher action: " |
| 263 | << static_cast<char>(action); |
Jorge E. Moreira | 7123e2e | 2019-09-05 13:47:29 -0700 | [diff] [blame] | 264 | auto response = cvd::LauncherResponse::kError; |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 265 | client->Write(&response, sizeof(response)); |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | } |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 270 | |
| 271 | std::string GetConfigFilePath(const vsoc::CuttlefishConfig& config) { |
| 272 | return config.PerInstancePath("cuttlefish_config.json"); |
| 273 | } |
| 274 | |
Greg Hartman | 98384ee | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 275 | } // namespace |
Jorge E. Moreira | 577383b | 2018-05-24 14:17:51 -0700 | [diff] [blame] | 276 | |
Cody Schuffelen | 0b2124b | 2019-09-16 18:04:17 -0700 | [diff] [blame] | 277 | int main(int argc, char** argv) { |
Jorge E. Moreira | 577383b | 2018-05-24 14:17:51 -0700 | [diff] [blame] | 278 | ::android::base::InitLogging(argv, android::base::StderrLogger); |
Cody Schuffelen | 0b2124b | 2019-09-16 18:04:17 -0700 | [diff] [blame] | 279 | google::ParseCommandLineFlags(&argc, &argv, false); |
Jorge E. Moreira | 3819324 | 2018-07-06 11:12:13 -0700 | [diff] [blame] | 280 | |
Cody Schuffelen | 5861bb3 | 2019-09-10 16:42:12 -0700 | [diff] [blame] | 281 | if (isatty(0)) { |
| 282 | LOG(FATAL) << "stdin was a tty, expected to be passed the output of a previous stage. " |
| 283 | << "Did you mean to run launch_cvd?"; |
| 284 | return cvd::RunnerExitCodes::kInvalidHostConfiguration; |
| 285 | } else { |
| 286 | int error_num = errno; |
| 287 | if (error_num == EBADF) { |
| 288 | LOG(FATAL) << "stdin was not a valid file descriptor, expected to be passed the output " |
| 289 | << "of assemble_cvd. Did you mean to run launch_cvd?"; |
| 290 | return cvd::RunnerExitCodes::kInvalidHostConfiguration; |
| 291 | } |
| 292 | } |
| 293 | |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 294 | std::string input_files_str; |
| 295 | { |
| 296 | auto input_fd = cvd::SharedFD::Dup(0); |
| 297 | auto bytes_read = cvd::ReadAll(input_fd, &input_files_str); |
| 298 | if (bytes_read < 0) { |
| 299 | LOG(FATAL) << "Failed to read input files. Error was \"" << input_fd->StrError() << "\""; |
| 300 | } |
| 301 | } |
Cody Schuffelen | f4a1cdb | 2019-11-13 16:51:16 -0800 | [diff] [blame] | 302 | std::vector<std::string> input_files = android::base::Split(input_files_str, "\n"); |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 303 | bool found_config = false; |
| 304 | for (const auto& file : input_files) { |
| 305 | if (file.find("cuttlefish_config.json") != std::string::npos) { |
| 306 | found_config = true; |
| 307 | setenv(vsoc::kCuttlefishConfigEnvVarName, file.c_str(), /* overwrite */ false); |
| 308 | } |
| 309 | } |
| 310 | if (!found_config) { |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 311 | return RunnerExitCodes::kCuttlefishConfigurationInitError; |
Cody Schuffelen | 147b88e | 2019-09-09 16:00:11 -0700 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | auto config = vsoc::CuttlefishConfig::Get(); |
Cody Schuffelen | 4524bba | 2019-01-29 15:57:59 -0800 | [diff] [blame] | 315 | |
Jorge E. Moreira | ec10b72 | 2019-09-06 18:52:22 -0700 | [diff] [blame] | 316 | // Change working directory to the instance directory as early as possible to |
| 317 | // ensure all host processes have the same working dir. This helps stop_cvd |
| 318 | // find the running processes when it can't establish a communication with the |
| 319 | // launcher. |
| 320 | auto chdir_ret = chdir(config->instance_dir().c_str()); |
| 321 | if (chdir_ret != 0) { |
| 322 | auto error = errno; |
| 323 | LOG(ERROR) << "Unable to change dir into instance directory (" |
| 324 | << config->instance_dir() << "): " << strerror(error); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 325 | return RunnerExitCodes::kInstanceDirCreationError; |
Jorge E. Moreira | ec10b72 | 2019-09-06 18:52:22 -0700 | [diff] [blame] | 326 | } |
| 327 | |
Jorge E. Moreira | 8832283 | 2018-07-22 16:41:01 -0700 | [diff] [blame] | 328 | auto vm_manager = vm_manager::VmManager::Get(config->vm_manager(), config); |
Jorge E. Moreira | 3819324 | 2018-07-06 11:12:13 -0700 | [diff] [blame] | 329 | |
Jorge E. Moreira | 5020a66 | 2018-07-09 17:07:14 -0700 | [diff] [blame] | 330 | // Check host configuration |
| 331 | std::vector<std::string> config_commands; |
| 332 | if (!vm_manager->ValidateHostConfiguration(&config_commands)) { |
| 333 | LOG(ERROR) << "Validation of user configuration failed"; |
| 334 | std::cout << "Execute the following to correctly configure:" << std::endl; |
| 335 | for (auto& command : config_commands) { |
| 336 | std::cout << " " << command << std::endl; |
| 337 | } |
| 338 | std::cout << "You may need to logout for the changes to take effect" |
| 339 | << std::endl; |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 340 | return RunnerExitCodes::kInvalidHostConfiguration; |
Jorge E. Moreira | 5020a66 | 2018-07-09 17:07:14 -0700 | [diff] [blame] | 341 | } |
| 342 | |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 343 | if (!WriteCuttlefishEnvironment(*config)) { |
Greg Hartman | 6abdbb9 | 2018-05-24 09:49:00 -0700 | [diff] [blame] | 344 | LOG(ERROR) << "Unable to write cuttlefish environment file"; |
| 345 | } |
| 346 | |
Jorge E. Moreira | cb7d46c | 2018-07-09 18:04:53 -0700 | [diff] [blame] | 347 | LOG(INFO) << "The following files contain useful debugging information:"; |
Cody Schuffelen | 5024973 | 2019-01-29 16:42:55 -0800 | [diff] [blame] | 348 | if (config->run_as_daemon()) { |
Jorge E. Moreira | 66f6ec8 | 2018-07-16 16:43:15 -0700 | [diff] [blame] | 349 | LOG(INFO) << " Launcher log: " << config->launcher_log_path(); |
| 350 | } |
Jorge E. Moreira | cb7d46c | 2018-07-09 18:04:53 -0700 | [diff] [blame] | 351 | LOG(INFO) << " Android's logcat output: " << config->logcat_path(); |
| 352 | LOG(INFO) << " Kernel log: " << config->PerInstancePath("kernel.log"); |
Jorge E. Moreira | a00584e | 2018-10-25 15:07:52 -0700 | [diff] [blame] | 353 | LOG(INFO) << " Instance configuration: " << GetConfigFilePath(*config); |
Jorge E. Moreira | cb7d46c | 2018-07-09 18:04:53 -0700 | [diff] [blame] | 354 | LOG(INFO) << " Instance environment: " << config->cuttlefish_env_path(); |
| 355 | LOG(INFO) << "To access the console run: socat file:$(tty),raw,echo=0 " |
| 356 | << config->console_path(); |
| 357 | |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 358 | auto launcher_monitor_path = config->launcher_monitor_socket_path(); |
| 359 | auto launcher_monitor_socket = cvd::SharedFD::SocketLocalServer( |
| 360 | launcher_monitor_path.c_str(), false, SOCK_STREAM, 0666); |
| 361 | if (!launcher_monitor_socket->IsOpen()) { |
Jorge E. Moreira | 81afca1 | 2018-07-26 16:48:49 -0700 | [diff] [blame] | 362 | LOG(ERROR) << "Error when opening launcher server: " |
| 363 | << launcher_monitor_socket->StrError(); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 364 | return cvd::RunnerExitCodes::kMonitorCreationFailed; |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 365 | } |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 366 | cvd::SharedFD foreground_launcher_pipe; |
Cody Schuffelen | 5024973 | 2019-01-29 16:42:55 -0800 | [diff] [blame] | 367 | if (config->run_as_daemon()) { |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 368 | foreground_launcher_pipe = DaemonizeLauncher(*config); |
| 369 | if (!foreground_launcher_pipe->IsOpen()) { |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 370 | return RunnerExitCodes::kDaemonizationError; |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 371 | } |
Jorge E. Moreira | 2363109 | 2018-07-17 10:51:25 -0700 | [diff] [blame] | 372 | } else { |
| 373 | // Make sure the launcher runs in its own process group even when running in |
| 374 | // foreground |
Jorge E. Moreira | 66e8ff9 | 2018-07-24 11:52:23 -0700 | [diff] [blame] | 375 | if (getsid(0) != getpid()) { |
| 376 | int retval = setpgid(0, 0); |
| 377 | if (retval) { |
| 378 | LOG(ERROR) << "Failed to create new process group: " << strerror(errno); |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 379 | std::exit(RunnerExitCodes::kProcessGroupError); |
Jorge E. Moreira | 66e8ff9 | 2018-07-24 11:52:23 -0700 | [diff] [blame] | 380 | } |
Jorge E. Moreira | 2363109 | 2018-07-17 10:51:25 -0700 | [diff] [blame] | 381 | } |
Jorge E. Moreira | 1300f0b | 2018-07-10 18:14:39 -0700 | [diff] [blame] | 382 | } |
| 383 | |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 384 | auto boot_state_machine = |
| 385 | std::make_shared<CvdBootStateMachine>(foreground_launcher_pipe); |
| 386 | |
Jorge E. Moreira | 1a62e76 | 2018-11-05 22:05:57 -0800 | [diff] [blame] | 387 | // Monitor and restart host processes supporting the CVD |
| 388 | cvd::ProcessMonitor process_monitor; |
| 389 | |
Jorge E. Moreira | 277e1c4 | 2019-05-06 17:24:27 -0700 | [diff] [blame] | 390 | auto event_pipes = |
| 391 | LaunchKernelLogMonitor(*config, &process_monitor, 2); |
| 392 | cvd::SharedFD boot_events_pipe = event_pipes[0]; |
| 393 | cvd::SharedFD adbd_events_pipe = event_pipes[1]; |
| 394 | event_pipes.clear(); |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 395 | |
Cody Schuffelen | b13869b | 2019-11-26 18:46:34 -0800 | [diff] [blame] | 396 | std::set<std::string> extra_kernel_cmdline; |
| 397 | |
Jorge E. Moreira | 734e1d1 | 2018-11-07 20:30:38 -0800 | [diff] [blame] | 398 | SetUpHandlingOfBootEvents(&process_monitor, boot_events_pipe, |
| 399 | boot_state_machine); |
| 400 | |
Cody Schuffelen | eb5c215 | 2019-12-05 15:44:49 -0800 | [diff] [blame] | 401 | auto logcat_server = LaunchLogcatReceiverIfEnabled(*config, &process_monitor); |
| 402 | auto logcat_server_args = KernelCommandLineFromLogcatServer(logcat_server); |
Jorge E. Moreira | fd10cae | 2019-02-19 15:35:42 -0800 | [diff] [blame] | 403 | |
Cody Schuffelen | c9183ba | 2019-12-05 15:23:46 -0800 | [diff] [blame] | 404 | auto config_server = LaunchConfigServer(*config, &process_monitor); |
| 405 | auto config_server_args = KernelCommandLineFromConfigServer(config_server); |
Jorge E. Moreira | f1f7cb3 | 2019-04-15 18:44:41 -0700 | [diff] [blame] | 406 | |
Cody Schuffelen | d3f27b9 | 2019-11-26 19:04:43 -0800 | [diff] [blame] | 407 | auto tombstone_server = LaunchTombstoneReceiverIfEnabled(*config, &process_monitor); |
| 408 | auto tombstone_kernel_args = KernelCommandLineFromTombstone(tombstone_server); |
Ram Muthiah | 792e2ad | 2019-04-19 11:19:46 -0700 | [diff] [blame] | 409 | |
Jorge E. Moreira | 7e1df15 | 2019-05-14 15:05:33 -0700 | [diff] [blame] | 410 | // The vnc server needs to be launched after the ivserver because it connects |
| 411 | // to it when using qemu. It needs to launch before the VMM because it serves |
| 412 | // on several sockets (input devices, vsock frame server) when using crosvm. |
Cody Schuffelen | b13869b | 2019-11-26 18:46:34 -0800 | [diff] [blame] | 413 | auto vnc_server_config = LaunchVNCServerIfEnabled( |
Jorge E. Moreira | 7e1df15 | 2019-05-14 15:05:33 -0700 | [diff] [blame] | 414 | *config, &process_monitor, GetOnSubprocessExitCallback(*config)); |
Cody Schuffelen | b13869b | 2019-11-26 18:46:34 -0800 | [diff] [blame] | 415 | auto vnc_kernel_args = KernelCommandLineFromVnc(vnc_server_config); |
| 416 | |
| 417 | auto kernel_args = KernelCommandLineFromConfig(*config); |
| 418 | kernel_args.insert(kernel_args.end(), vnc_kernel_args.begin(), vnc_kernel_args.end()); |
Cody Schuffelen | d3f27b9 | 2019-11-26 19:04:43 -0800 | [diff] [blame] | 419 | kernel_args.insert(kernel_args.end(), tombstone_kernel_args.begin(), |
| 420 | tombstone_kernel_args.end()); |
Cody Schuffelen | c9183ba | 2019-12-05 15:23:46 -0800 | [diff] [blame] | 421 | kernel_args.insert(kernel_args.end(), config_server_args.begin(), config_server_args.end()); |
Cody Schuffelen | eb5c215 | 2019-12-05 15:44:49 -0800 | [diff] [blame] | 422 | kernel_args.insert(kernel_args.end(), logcat_server_args.begin(), logcat_server_args.end()); |
Jorge E. Moreira | 7e1df15 | 2019-05-14 15:05:33 -0700 | [diff] [blame] | 423 | |
Jorge E. Moreira | 9aeb97d | 2019-01-28 23:19:02 -0800 | [diff] [blame] | 424 | // Start the guest VM |
Cody Schuffelen | b13869b | 2019-11-26 18:46:34 -0800 | [diff] [blame] | 425 | vm_manager->WithFrontend(vnc_kernel_args.size() > 0); |
Cody Schuffelen | 2de6ead | 2019-12-04 16:16:47 -0800 | [diff] [blame] | 426 | vm_manager->WithKernelCommandLine(android::base::Join(kernel_args, " ")); |
Cody Schuffelen | 97359f8 | 2019-11-26 18:40:15 -0800 | [diff] [blame] | 427 | auto vmm_commands = vm_manager->StartCommands(); |
Jorge E. Moreira | 13cbd98 | 2019-06-06 16:06:34 -0700 | [diff] [blame] | 428 | for (auto& vmm_cmd: vmm_commands) { |
| 429 | process_monitor.StartSubprocess(std::move(vmm_cmd), |
| 430 | GetOnSubprocessExitCallback(*config)); |
| 431 | } |
Jorge E. Moreira | 4ca884e | 2018-01-25 16:57:48 -0800 | [diff] [blame] | 432 | |
Jorge E. Moreira | 9aeb97d | 2019-01-28 23:19:02 -0800 | [diff] [blame] | 433 | // Start other host processes |
Cody Schuffelen | d12e0c9 | 2019-01-29 15:44:45 -0800 | [diff] [blame] | 434 | LaunchSocketVsockProxyIfEnabled(&process_monitor, *config); |
Jorge E. Moreira | 9ec1585 | 2019-05-02 17:52:58 -0700 | [diff] [blame] | 435 | LaunchAdbConnectorIfEnabled(&process_monitor, *config, adbd_events_pipe); |
Andreas Huber | 21b7af5 | 2018-03-01 10:01:55 -0800 | [diff] [blame] | 436 | |
Jorge E. Moreira | 7123e2e | 2019-09-05 13:47:29 -0700 | [diff] [blame] | 437 | ServerLoop(launcher_monitor_socket, &process_monitor); // Should not return |
Jorge E. Moreira | 50a0775 | 2018-07-18 18:49:04 -0700 | [diff] [blame] | 438 | LOG(ERROR) << "The server loop returned, it should never happen!!"; |
Cody Schuffelen | a9d9a86 | 2019-09-10 16:16:06 -0700 | [diff] [blame] | 439 | return cvd::RunnerExitCodes::kServerError; |
Romit Dasgupta | 61b572a | 2017-06-23 17:48:22 -0700 | [diff] [blame] | 440 | } |