|  | 
 | /* | 
 |  * Copyright (C) 2020 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include "src/profiling/symbolizer/subprocess.h" | 
 |  | 
 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) | 
 |  | 
 | #include <sstream> | 
 | #include <string> | 
 |  | 
 | #include <Windows.h> | 
 |  | 
 | #include "perfetto/base/logging.h" | 
 |  | 
 | namespace perfetto { | 
 | namespace profiling { | 
 |  | 
 | Subprocess::Subprocess(const std::string& file, std::vector<std::string> args) { | 
 |   std::stringstream cmd; | 
 |   cmd << file; | 
 |   for (auto arg : args) { | 
 |     cmd << " " << arg; | 
 |   } | 
 |   SECURITY_ATTRIBUTES attr; | 
 |   attr.nLength = sizeof(SECURITY_ATTRIBUTES); | 
 |   attr.bInheritHandle = true; | 
 |   attr.lpSecurityDescriptor = nullptr; | 
 |   // Create a pipe for the child process's STDOUT. | 
 |   if (!CreatePipe(&child_pipe_out_read_, &child_pipe_out_write_, &attr, 0) || | 
 |       !SetHandleInformation(child_pipe_out_read_, HANDLE_FLAG_INHERIT, 0)) { | 
 |     PERFETTO_ELOG("Failed to create stdout pipe"); | 
 |     return; | 
 |   } | 
 |   if (!CreatePipe(&child_pipe_in_read_, &child_pipe_in_write_, &attr, 0) || | 
 |       !SetHandleInformation(child_pipe_in_write_, HANDLE_FLAG_INHERIT, 0)) { | 
 |     PERFETTO_ELOG("Failed to create stdin pipe"); | 
 |     return; | 
 |   } | 
 |  | 
 |   PROCESS_INFORMATION proc_info; | 
 |   STARTUPINFOA start_info; | 
 |   bool success = false; | 
 |   // Set up members of the PROCESS_INFORMATION structure. | 
 |   ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); | 
 |  | 
 |   // Set up members of the STARTUPINFO structure. | 
 |   // This structure specifies the STDIN and STDOUT handles for redirection. | 
 |   ZeroMemory(&start_info, sizeof(STARTUPINFOA)); | 
 |   start_info.cb = sizeof(STARTUPINFOA); | 
 |   start_info.hStdError = child_pipe_out_write_; | 
 |   start_info.hStdOutput = child_pipe_out_write_; | 
 |   start_info.hStdInput = child_pipe_in_read_; | 
 |   start_info.dwFlags |= STARTF_USESTDHANDLES; | 
 |  | 
 |   // Create the child process. | 
 |   success = CreateProcessA(nullptr, | 
 |                            &(cmd.str()[0]),  // command line | 
 |                            nullptr,          // process security attributes | 
 |                            nullptr,      // primary thread security attributes | 
 |                            TRUE,         // handles are inherited | 
 |                            0,            // creation flags | 
 |                            nullptr,      // use parent's environment | 
 |                            nullptr,      // use parent's current directory | 
 |                            &start_info,  // STARTUPINFO pointer | 
 |                            &proc_info);  // receives PROCESS_INFORMATION | 
 |  | 
 |   // If an error occurs, exit the application. | 
 |   if (success) { | 
 |     CloseHandle(proc_info.hProcess); | 
 |     CloseHandle(proc_info.hThread); | 
 |  | 
 |     // Close handles to the stdin and stdout pipes no longer needed by the child | 
 |     // process. If they are not explicitly closed, there is no way to recognize | 
 |     // that the child process has ended. | 
 |  | 
 |     CloseHandle(child_pipe_out_write_); | 
 |     CloseHandle(child_pipe_in_read_); | 
 |   } else { | 
 |     PERFETTO_ELOG("Failed to launch: %s", cmd.str().c_str()); | 
 |     child_pipe_in_read_ = nullptr; | 
 |     child_pipe_in_write_ = nullptr; | 
 |     child_pipe_out_write_ = nullptr; | 
 |     child_pipe_out_read_ = nullptr; | 
 |   } | 
 | } | 
 |  | 
 | Subprocess::~Subprocess() { | 
 |   CloseHandle(child_pipe_out_read_); | 
 |   CloseHandle(child_pipe_in_write_); | 
 | } | 
 |  | 
 | int64_t Subprocess::Write(const char* buffer, size_t size) { | 
 |   if (child_pipe_in_write_ == nullptr) { | 
 |     return -1; | 
 |   } | 
 |   DWORD bytes_written; | 
 |   if (WriteFile(child_pipe_in_write_, buffer, static_cast<DWORD>(size), | 
 |                 &bytes_written, nullptr)) { | 
 |     return static_cast<int64_t>(bytes_written); | 
 |   } | 
 |   return -1; | 
 | } | 
 |  | 
 | int64_t Subprocess::Read(char* buffer, size_t size) { | 
 |   if (child_pipe_out_read_ == nullptr) { | 
 |     return -1; | 
 |   } | 
 |   DWORD bytes_read; | 
 |   if (ReadFile(child_pipe_out_read_, buffer, static_cast<DWORD>(size), | 
 |                &bytes_read, nullptr)) { | 
 |     return static_cast<int64_t>(bytes_read); | 
 |   } | 
 |   return -1; | 
 | } | 
 |  | 
 | }  // namespace profiling | 
 | }  // namespace perfetto | 
 |  | 
 | #endif  // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |