xref: /aosp_15_r20/external/perfetto/src/profiling/symbolizer/subprocess_windows.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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