1*6dbdd20aSAndroid Build Coastguard Worker
2*6dbdd20aSAndroid Build Coastguard Worker /*
3*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
4*6dbdd20aSAndroid Build Coastguard Worker *
5*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*6dbdd20aSAndroid Build Coastguard Worker *
9*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*6dbdd20aSAndroid Build Coastguard Worker *
11*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
16*6dbdd20aSAndroid Build Coastguard Worker */
17*6dbdd20aSAndroid Build Coastguard Worker
18*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/symbolizer/subprocess.h"
19*6dbdd20aSAndroid Build Coastguard Worker
20*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
21*6dbdd20aSAndroid Build Coastguard Worker
22*6dbdd20aSAndroid Build Coastguard Worker #include <sstream>
23*6dbdd20aSAndroid Build Coastguard Worker #include <string>
24*6dbdd20aSAndroid Build Coastguard Worker
25*6dbdd20aSAndroid Build Coastguard Worker #include <Windows.h>
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
30*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
31*6dbdd20aSAndroid Build Coastguard Worker
Subprocess(const std::string & file,std::vector<std::string> args)32*6dbdd20aSAndroid Build Coastguard Worker Subprocess::Subprocess(const std::string& file, std::vector<std::string> args) {
33*6dbdd20aSAndroid Build Coastguard Worker std::stringstream cmd;
34*6dbdd20aSAndroid Build Coastguard Worker cmd << file;
35*6dbdd20aSAndroid Build Coastguard Worker for (auto arg : args) {
36*6dbdd20aSAndroid Build Coastguard Worker cmd << " " << arg;
37*6dbdd20aSAndroid Build Coastguard Worker }
38*6dbdd20aSAndroid Build Coastguard Worker SECURITY_ATTRIBUTES attr;
39*6dbdd20aSAndroid Build Coastguard Worker attr.nLength = sizeof(SECURITY_ATTRIBUTES);
40*6dbdd20aSAndroid Build Coastguard Worker attr.bInheritHandle = true;
41*6dbdd20aSAndroid Build Coastguard Worker attr.lpSecurityDescriptor = nullptr;
42*6dbdd20aSAndroid Build Coastguard Worker // Create a pipe for the child process's STDOUT.
43*6dbdd20aSAndroid Build Coastguard Worker if (!CreatePipe(&child_pipe_out_read_, &child_pipe_out_write_, &attr, 0) ||
44*6dbdd20aSAndroid Build Coastguard Worker !SetHandleInformation(child_pipe_out_read_, HANDLE_FLAG_INHERIT, 0)) {
45*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to create stdout pipe");
46*6dbdd20aSAndroid Build Coastguard Worker return;
47*6dbdd20aSAndroid Build Coastguard Worker }
48*6dbdd20aSAndroid Build Coastguard Worker if (!CreatePipe(&child_pipe_in_read_, &child_pipe_in_write_, &attr, 0) ||
49*6dbdd20aSAndroid Build Coastguard Worker !SetHandleInformation(child_pipe_in_write_, HANDLE_FLAG_INHERIT, 0)) {
50*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to create stdin pipe");
51*6dbdd20aSAndroid Build Coastguard Worker return;
52*6dbdd20aSAndroid Build Coastguard Worker }
53*6dbdd20aSAndroid Build Coastguard Worker
54*6dbdd20aSAndroid Build Coastguard Worker PROCESS_INFORMATION proc_info;
55*6dbdd20aSAndroid Build Coastguard Worker STARTUPINFOA start_info;
56*6dbdd20aSAndroid Build Coastguard Worker bool success = false;
57*6dbdd20aSAndroid Build Coastguard Worker // Set up members of the PROCESS_INFORMATION structure.
58*6dbdd20aSAndroid Build Coastguard Worker ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
59*6dbdd20aSAndroid Build Coastguard Worker
60*6dbdd20aSAndroid Build Coastguard Worker // Set up members of the STARTUPINFO structure.
61*6dbdd20aSAndroid Build Coastguard Worker // This structure specifies the STDIN and STDOUT handles for redirection.
62*6dbdd20aSAndroid Build Coastguard Worker ZeroMemory(&start_info, sizeof(STARTUPINFOA));
63*6dbdd20aSAndroid Build Coastguard Worker start_info.cb = sizeof(STARTUPINFOA);
64*6dbdd20aSAndroid Build Coastguard Worker start_info.hStdError = child_pipe_out_write_;
65*6dbdd20aSAndroid Build Coastguard Worker start_info.hStdOutput = child_pipe_out_write_;
66*6dbdd20aSAndroid Build Coastguard Worker start_info.hStdInput = child_pipe_in_read_;
67*6dbdd20aSAndroid Build Coastguard Worker start_info.dwFlags |= STARTF_USESTDHANDLES;
68*6dbdd20aSAndroid Build Coastguard Worker
69*6dbdd20aSAndroid Build Coastguard Worker // Create the child process.
70*6dbdd20aSAndroid Build Coastguard Worker success = CreateProcessA(nullptr,
71*6dbdd20aSAndroid Build Coastguard Worker &(cmd.str()[0]), // command line
72*6dbdd20aSAndroid Build Coastguard Worker nullptr, // process security attributes
73*6dbdd20aSAndroid Build Coastguard Worker nullptr, // primary thread security attributes
74*6dbdd20aSAndroid Build Coastguard Worker TRUE, // handles are inherited
75*6dbdd20aSAndroid Build Coastguard Worker 0, // creation flags
76*6dbdd20aSAndroid Build Coastguard Worker nullptr, // use parent's environment
77*6dbdd20aSAndroid Build Coastguard Worker nullptr, // use parent's current directory
78*6dbdd20aSAndroid Build Coastguard Worker &start_info, // STARTUPINFO pointer
79*6dbdd20aSAndroid Build Coastguard Worker &proc_info); // receives PROCESS_INFORMATION
80*6dbdd20aSAndroid Build Coastguard Worker
81*6dbdd20aSAndroid Build Coastguard Worker // If an error occurs, exit the application.
82*6dbdd20aSAndroid Build Coastguard Worker if (success) {
83*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(proc_info.hProcess);
84*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(proc_info.hThread);
85*6dbdd20aSAndroid Build Coastguard Worker
86*6dbdd20aSAndroid Build Coastguard Worker // Close handles to the stdin and stdout pipes no longer needed by the child
87*6dbdd20aSAndroid Build Coastguard Worker // process. If they are not explicitly closed, there is no way to recognize
88*6dbdd20aSAndroid Build Coastguard Worker // that the child process has ended.
89*6dbdd20aSAndroid Build Coastguard Worker
90*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(child_pipe_out_write_);
91*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(child_pipe_in_read_);
92*6dbdd20aSAndroid Build Coastguard Worker } else {
93*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to launch: %s", cmd.str().c_str());
94*6dbdd20aSAndroid Build Coastguard Worker child_pipe_in_read_ = nullptr;
95*6dbdd20aSAndroid Build Coastguard Worker child_pipe_in_write_ = nullptr;
96*6dbdd20aSAndroid Build Coastguard Worker child_pipe_out_write_ = nullptr;
97*6dbdd20aSAndroid Build Coastguard Worker child_pipe_out_read_ = nullptr;
98*6dbdd20aSAndroid Build Coastguard Worker }
99*6dbdd20aSAndroid Build Coastguard Worker }
100*6dbdd20aSAndroid Build Coastguard Worker
~Subprocess()101*6dbdd20aSAndroid Build Coastguard Worker Subprocess::~Subprocess() {
102*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(child_pipe_out_read_);
103*6dbdd20aSAndroid Build Coastguard Worker CloseHandle(child_pipe_in_write_);
104*6dbdd20aSAndroid Build Coastguard Worker }
105*6dbdd20aSAndroid Build Coastguard Worker
Write(const char * buffer,size_t size)106*6dbdd20aSAndroid Build Coastguard Worker int64_t Subprocess::Write(const char* buffer, size_t size) {
107*6dbdd20aSAndroid Build Coastguard Worker if (child_pipe_in_write_ == nullptr) {
108*6dbdd20aSAndroid Build Coastguard Worker return -1;
109*6dbdd20aSAndroid Build Coastguard Worker }
110*6dbdd20aSAndroid Build Coastguard Worker DWORD bytes_written;
111*6dbdd20aSAndroid Build Coastguard Worker if (WriteFile(child_pipe_in_write_, buffer, static_cast<DWORD>(size),
112*6dbdd20aSAndroid Build Coastguard Worker &bytes_written, nullptr)) {
113*6dbdd20aSAndroid Build Coastguard Worker return static_cast<int64_t>(bytes_written);
114*6dbdd20aSAndroid Build Coastguard Worker }
115*6dbdd20aSAndroid Build Coastguard Worker return -1;
116*6dbdd20aSAndroid Build Coastguard Worker }
117*6dbdd20aSAndroid Build Coastguard Worker
Read(char * buffer,size_t size)118*6dbdd20aSAndroid Build Coastguard Worker int64_t Subprocess::Read(char* buffer, size_t size) {
119*6dbdd20aSAndroid Build Coastguard Worker if (child_pipe_out_read_ == nullptr) {
120*6dbdd20aSAndroid Build Coastguard Worker return -1;
121*6dbdd20aSAndroid Build Coastguard Worker }
122*6dbdd20aSAndroid Build Coastguard Worker DWORD bytes_read;
123*6dbdd20aSAndroid Build Coastguard Worker if (ReadFile(child_pipe_out_read_, buffer, static_cast<DWORD>(size),
124*6dbdd20aSAndroid Build Coastguard Worker &bytes_read, nullptr)) {
125*6dbdd20aSAndroid Build Coastguard Worker return static_cast<int64_t>(bytes_read);
126*6dbdd20aSAndroid Build Coastguard Worker }
127*6dbdd20aSAndroid Build Coastguard Worker return -1;
128*6dbdd20aSAndroid Build Coastguard Worker }
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling
131*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
132*6dbdd20aSAndroid Build Coastguard Worker
133*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
134