blob: 7f28ea441344a5f0b6f2227ae47f05595b8124a9 [file] [log] [blame] [edit]
/*
* 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)