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