blob: 6b4956d998798c61cf1952a4ef82d5615a90f496 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/chrome_cleaner/os/process.h"
#include <windows.h>
#include <psapi.h>
#include <vector>
#include "base/logging.h"
namespace chrome_cleaner {
bool GetLoadedModuleFileNames(HANDLE process,
std::set<base::string16>* module_names) {
std::vector<HMODULE> module_handles;
size_t modules_count = 128;
// Adjust array size for all modules to fit into it.
do {
// Allocate more space than needed in case more modules were loaded between
// calls to EnumProcessModulesEx.
modules_count *= 2;
module_handles.resize(modules_count);
DWORD bytes_needed;
if (!::EnumProcessModulesEx(process, module_handles.data(),
modules_count * sizeof(HMODULE), &bytes_needed,
LIST_MODULES_ALL)) {
PLOG(ERROR) << "Failed to enumerate modules";
return false;
}
DCHECK_EQ(bytes_needed % sizeof(HMODULE), 0U);
modules_count = bytes_needed / sizeof(HMODULE);
} while (modules_count > module_handles.size());
DCHECK(module_names);
wchar_t module_name[MAX_PATH];
for (size_t i = 0; i < modules_count; ++i) {
size_t module_name_length = ::GetModuleFileNameExW(
process, module_handles[i], module_name, MAX_PATH);
if (module_name_length == 0) {
PLOG(ERROR) << "Failed to get module filename";
continue;
}
module_names->insert(base::string16(module_name, module_name_length));
}
return true;
}
bool GetProcessExecutablePath(HANDLE process, base::string16* path) {
DCHECK(path);
std::vector<wchar_t> image_path(MAX_PATH);
DWORD path_length = image_path.size();
BOOL success =
::QueryFullProcessImageName(process, 0, image_path.data(), &path_length);
if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
// Process name is potentially greater than MAX_PATH, try larger max size.
image_path.resize(SHRT_MAX);
path_length = image_path.size();
success = ::QueryFullProcessImageName(process, 0, image_path.data(),
&path_length);
}
if (!success) {
PLOG_IF(ERROR, ::GetLastError() != ERROR_GEN_FAILURE)
<< "Failed to get process image path";
return false;
}
path->assign(image_path.data(), path_length);
return true;
}
bool GetSystemResourceUsage(HANDLE process, SystemResourceUsage* stats) {
DCHECK(stats);
FILETIME creation_time;
FILETIME exit_time;
FILETIME kernel_time;
FILETIME user_time;
// The returned user and kernel times are to be interpreted as time
// durations and not as time points. |base::Time| can convert from FILETIME
// to |base::Time| and by subtracting from time zero, we get the duration as
// a |base::TimeDelta|.
if (!::GetProcessTimes(process, &creation_time, &exit_time, &kernel_time,
&user_time)) {
PLOG(ERROR) << "Could not get process times";
return false;
}
stats->kernel_time = base::Time::FromFileTime(kernel_time) - base::Time();
stats->user_time = base::Time::FromFileTime(user_time) - base::Time();
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(process));
if (!metrics || !metrics->GetIOCounters(&stats->io_counters)) {
LOG(ERROR) << "Failed to get IO process counters";
return false;
}
PROCESS_MEMORY_COUNTERS pmc;
if (::GetProcessMemoryInfo(::GetCurrentProcess(), &pmc, sizeof(pmc))) {
stats->peak_working_set_size = pmc.PeakWorkingSetSize / 1024;
}
return true;
}
} // namespace chrome_cleaner