1 /*
2 * Copyright (C) 2020 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 "perfetto/ext/base/subprocess.h"
18
19 #include "perfetto/base/build_config.h"
20
21 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
22
23 #include <stdio.h>
24
25 #include <algorithm>
26 #include <mutex>
27 #include <tuple>
28
29 #include <Windows.h>
30
31 #include "perfetto/base/logging.h"
32 #include "perfetto/base/time.h"
33 #include "perfetto/ext/base/pipe.h"
34 #include "perfetto/ext/base/utils.h"
35
36 namespace perfetto {
37 namespace base {
38
39 // static
40 const int Subprocess::kTimeoutSignal = static_cast<int>(STATUS_TIMEOUT);
41
Start()42 void Subprocess::Start() {
43 if (args.exec_cmd.empty()) {
44 PERFETTO_ELOG("Subprocess.exec_cmd cannot be empty on Windows");
45 return;
46 }
47
48 // Quote arguments but only when ambiguous. When quoting, CreateProcess()
49 // assumes that the command is an absolute path and does not search in the
50 // %PATH%. If non quoted, instead, CreateProcess() tries both. This is to
51 // allow Subprocess("cmd.exe", "/c", "shell command").
52 std::string cmd;
53 for (const auto& part : args.exec_cmd) {
54 if (part.find(" ") != std::string::npos) {
55 cmd += "\"" + part + "\" ";
56 } else {
57 cmd += part + " ";
58 }
59 }
60 // Remove trailing space.
61 if (!cmd.empty())
62 cmd.resize(cmd.size() - 1);
63
64 if (args.stdin_mode == InputMode::kBuffer) {
65 s_->stdin_pipe = Pipe::Create();
66 // Allow the child process to inherit the other end of the pipe.
67 PERFETTO_CHECK(
68 ::SetHandleInformation(*s_->stdin_pipe.rd, HANDLE_FLAG_INHERIT, 1));
69 }
70
71 if (args.stderr_mode == OutputMode::kBuffer ||
72 args.stdout_mode == OutputMode::kBuffer) {
73 s_->stdouterr_pipe = Pipe::Create();
74 PERFETTO_CHECK(
75 ::SetHandleInformation(*s_->stdouterr_pipe.wr, HANDLE_FLAG_INHERIT, 1));
76 }
77
78 ScopedPlatformHandle nul_handle;
79 if (args.stderr_mode == OutputMode::kDevNull ||
80 args.stdout_mode == OutputMode::kDevNull) {
81 nul_handle.reset(::CreateFileA(
82 "NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
83 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
84 PERFETTO_CHECK(::SetHandleInformation(*nul_handle, HANDLE_FLAG_INHERIT, 1));
85 }
86
87 PROCESS_INFORMATION proc_info{};
88 STARTUPINFOA start_info{};
89 start_info.cb = sizeof(STARTUPINFOA);
90
91 if (args.stderr_mode == OutputMode::kInherit) {
92 start_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
93 } else if (args.stderr_mode == OutputMode::kBuffer) {
94 start_info.hStdError = *s_->stdouterr_pipe.wr;
95 } else if (args.stderr_mode == OutputMode::kDevNull) {
96 start_info.hStdError = *nul_handle;
97 } else if (args.stderr_mode == OutputMode::kFd) {
98 PERFETTO_CHECK(
99 ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
100 start_info.hStdError = *args.out_fd;
101 } else {
102 PERFETTO_CHECK(false);
103 }
104
105 if (args.stdout_mode == OutputMode::kInherit) {
106 start_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
107 } else if (args.stdout_mode == OutputMode::kBuffer) {
108 start_info.hStdOutput = *s_->stdouterr_pipe.wr;
109 } else if (args.stdout_mode == OutputMode::kDevNull) {
110 start_info.hStdOutput = *nul_handle;
111 } else if (args.stdout_mode == OutputMode::kFd) {
112 PERFETTO_CHECK(
113 ::SetHandleInformation(*args.out_fd, HANDLE_FLAG_INHERIT, 1));
114 start_info.hStdOutput = *args.out_fd;
115 } else {
116 PERFETTO_CHECK(false);
117 }
118
119 if (args.stdin_mode == InputMode::kBuffer) {
120 start_info.hStdInput = *s_->stdin_pipe.rd;
121 } else if (args.stdin_mode == InputMode::kDevNull) {
122 start_info.hStdInput = *nul_handle;
123 }
124
125 start_info.dwFlags |= STARTF_USESTDHANDLES;
126
127 // Create the child process.
128 bool success =
129 ::CreateProcessA(nullptr, // App name. Needs to be null to use PATH.
130 &cmd[0], // Command line.
131 nullptr, // Process security attributes.
132 nullptr, // Primary thread security attributes.
133 true, // Handles are inherited.
134 0, // Flags.
135 nullptr, // Use parent's environment.
136 nullptr, // Use parent's current directory.
137 &start_info, // STARTUPINFO pointer.
138 &proc_info); // Receives PROCESS_INFORMATION.
139
140 // Close on our side the pipe ends that we passed to the child process.
141 s_->stdin_pipe.rd.reset();
142 s_->stdouterr_pipe.wr.reset();
143 args.out_fd.reset();
144
145 if (!success) {
146 s_->returncode = ERROR_FILE_NOT_FOUND;
147 s_->status = kTerminated;
148 s_->stdin_pipe.wr.reset();
149 s_->stdouterr_pipe.rd.reset();
150 PERFETTO_ELOG("CreateProcess failed: %lx, cmd: %s", GetLastError(),
151 &cmd[0]);
152 return;
153 }
154
155 s_->pid = proc_info.dwProcessId;
156 s_->win_proc_handle = ScopedPlatformHandle(proc_info.hProcess);
157 s_->win_thread_handle = ScopedPlatformHandle(proc_info.hThread);
158 s_->status = kRunning;
159
160 MovableState* s = s_.get();
161 if (args.stdin_mode == InputMode::kBuffer) {
162 s_->stdin_thread = std::thread(&Subprocess::StdinThread, s, args.input);
163 }
164
165 if (args.stderr_mode == OutputMode::kBuffer ||
166 args.stdout_mode == OutputMode::kBuffer) {
167 PERFETTO_DCHECK(s_->stdouterr_pipe.rd);
168 s_->stdouterr_thread = std::thread(&Subprocess::StdoutErrThread, s);
169 }
170 }
171
172 // static
StdinThread(MovableState * s,std::string input)173 void Subprocess::StdinThread(MovableState* s, std::string input) {
174 size_t input_written = 0;
175 while (input_written < input.size()) {
176 DWORD wsize = 0;
177 if (::WriteFile(*s->stdin_pipe.wr, input.data() + input_written,
178 static_cast<DWORD>(input.size() - input_written), &wsize,
179 nullptr)) {
180 input_written += wsize;
181 } else {
182 // ERROR_BROKEN_PIPE is WAI when the child just closes stdin and stops
183 // accepting input.
184 auto err = ::GetLastError();
185 if (err != ERROR_BROKEN_PIPE)
186 PERFETTO_PLOG("Subprocess WriteFile(stdin) failed %lx", err);
187 break;
188 }
189 } // while(...)
190 std::unique_lock<std::mutex> lock(s->mutex);
191 s->stdin_pipe.wr.reset();
192 }
193
194 // static
StdoutErrThread(MovableState * s)195 void Subprocess::StdoutErrThread(MovableState* s) {
196 char buf[4096];
197 for (;;) {
198 DWORD rsize = 0;
199 bool res =
200 ::ReadFile(*s->stdouterr_pipe.rd, buf, sizeof(buf), &rsize, nullptr);
201 if (!res) {
202 auto err = GetLastError();
203 if (err != ERROR_BROKEN_PIPE)
204 PERFETTO_PLOG("Subprocess ReadFile(stdouterr) failed %ld", err);
205 }
206
207 if (rsize > 0) {
208 std::unique_lock<std::mutex> lock(s->mutex);
209 s->locked_outerr_buf.append(buf, static_cast<size_t>(rsize));
210 } else { // EOF or some error.
211 break;
212 }
213 } // For(..)
214
215 // Close the stdouterr_pipe. The main loop looks at the pipe closure to
216 // determine whether the stdout/err thread has completed.
217 {
218 std::unique_lock<std::mutex> lock(s->mutex);
219 s->stdouterr_pipe.rd.reset();
220 }
221 s->stdouterr_done_event.Notify();
222 }
223
Poll()224 Subprocess::Status Subprocess::Poll() {
225 if (s_->status != kRunning)
226 return s_->status; // Nothing to poll.
227 Wait(1 /*ms*/);
228 return s_->status;
229 }
230
Wait(int timeout_ms)231 bool Subprocess::Wait(int timeout_ms) {
232 PERFETTO_CHECK(s_->status != kNotStarted);
233 const bool wait_forever = timeout_ms == 0;
234 const int64_t wait_start_ms = base::GetWallTimeMs().count();
235
236 // Break out of the loop only after both conditions are satisfied:
237 // - All stdout/stderr data has been read (if OutputMode::kBuffer).
238 // - The process exited.
239 // Note that the two events can happen arbitrary order. After the process
240 // exits, there might be still data in the pipe buffer, which we want to
241 // read fully.
242 // Note also that stdout/err might be "complete" before starting, if neither
243 // is operating in OutputMode::kBuffer mode. In that case we just want to wait
244 // for the process termination.
245 //
246 // Instead, don't wait on the stdin to be fully written. The child process
247 // might exit prematurely (or crash). If that happens, we can end up in a
248 // state where the write(stdin_pipe_.wr) will never unblock.
249 bool stdouterr_complete = false;
250 for (;;) {
251 HANDLE wait_handles[2]{};
252 DWORD num_handles = 0;
253
254 // Check if the process exited.
255 bool process_exited = !s_->win_proc_handle;
256 if (!process_exited) {
257 DWORD exit_code = STILL_ACTIVE;
258 PERFETTO_CHECK(::GetExitCodeProcess(*s_->win_proc_handle, &exit_code));
259 if (exit_code != STILL_ACTIVE) {
260 s_->returncode = static_cast<int>(exit_code);
261 s_->status = kTerminated;
262 s_->win_proc_handle.reset();
263 s_->win_thread_handle.reset();
264 process_exited = true;
265 }
266 } else {
267 PERFETTO_DCHECK(s_->status != kRunning);
268 }
269 if (!process_exited) {
270 wait_handles[num_handles++] = *s_->win_proc_handle;
271 }
272
273 // Check if there is more output and if the stdout/err pipe has been closed.
274 {
275 std::unique_lock<std::mutex> lock(s_->mutex);
276 // Move the output from the internal buffer shared with the
277 // stdouterr_thread to the final buffer exposed to the client.
278 if (!s_->locked_outerr_buf.empty()) {
279 s_->output.append(std::move(s_->locked_outerr_buf));
280 s_->locked_outerr_buf.clear();
281 }
282 stdouterr_complete = !s_->stdouterr_pipe.rd;
283 if (!stdouterr_complete) {
284 wait_handles[num_handles++] = s_->stdouterr_done_event.fd();
285 }
286 } // lock(s_->mutex)
287
288 if (num_handles == 0) {
289 PERFETTO_DCHECK(process_exited && stdouterr_complete);
290 break;
291 }
292
293 DWORD wait_ms; // Note: DWORD is unsigned.
294 if (wait_forever) {
295 wait_ms = INFINITE;
296 } else {
297 const int64_t now = GetWallTimeMs().count();
298 const int64_t wait_left_ms = timeout_ms - (now - wait_start_ms);
299 if (wait_left_ms <= 0)
300 return false; // Timed out
301 wait_ms = static_cast<DWORD>(wait_left_ms);
302 }
303
304 auto wait_res =
305 ::WaitForMultipleObjects(num_handles, wait_handles, false, wait_ms);
306 PERFETTO_CHECK(wait_res != WAIT_FAILED);
307 }
308
309 PERFETTO_DCHECK(!s_->win_proc_handle);
310 PERFETTO_DCHECK(!s_->win_thread_handle);
311
312 if (s_->stdin_thread.joinable()) // Might not exist if CreateProcess failed.
313 s_->stdin_thread.join();
314 if (s_->stdouterr_thread.joinable())
315 s_->stdouterr_thread.join();
316
317 // The stdin pipe is closed by the dedicated stdin thread. However if that is
318 // not started (e.g. because of no redirection) force close it now. Needs to
319 // happen after the join() to be thread safe.
320 s_->stdin_pipe.wr.reset();
321 s_->stdouterr_pipe.rd.reset();
322
323 return true;
324 }
325
KillAndWaitForTermination(int exit_code)326 void Subprocess::KillAndWaitForTermination(int exit_code) {
327 auto code = exit_code ? static_cast<DWORD>(exit_code) : STATUS_CONTROL_C_EXIT;
328 ::TerminateProcess(*s_->win_proc_handle, code);
329 Wait();
330 // TryReadExitStatus must have joined the threads.
331 PERFETTO_DCHECK(!s_->stdin_thread.joinable());
332 PERFETTO_DCHECK(!s_->stdouterr_thread.joinable());
333 }
334
335 } // namespace base
336 } // namespace perfetto
337
338 #endif // PERFETTO_OS_WIN
339