1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/chrome_cleaner/os/process.h"
6
7 #include <windows.h>
8
9 #include <psapi.h>
10
11 #include <vector>
12
13 #include "base/logging.h"
14
15 namespace chrome_cleaner {
16
GetLoadedModuleFileNames(HANDLE process,std::set<std::wstring> * module_names)17 bool GetLoadedModuleFileNames(HANDLE process,
18 std::set<std::wstring>* module_names) {
19 std::vector<HMODULE> module_handles;
20 size_t modules_count = 128;
21 // Adjust array size for all modules to fit into it.
22 do {
23 // Allocate more space than needed in case more modules were loaded between
24 // calls to EnumProcessModulesEx.
25 modules_count *= 2;
26 module_handles.resize(modules_count);
27 DWORD bytes_needed;
28 if (!::EnumProcessModulesEx(process, module_handles.data(),
29 modules_count * sizeof(HMODULE), &bytes_needed,
30 LIST_MODULES_ALL)) {
31 PLOG(ERROR) << "Failed to enumerate modules";
32 return false;
33 }
34 DCHECK_EQ(bytes_needed % sizeof(HMODULE), 0U);
35 modules_count = bytes_needed / sizeof(HMODULE);
36 } while (modules_count > module_handles.size());
37
38 DCHECK(module_names);
39 wchar_t module_name[MAX_PATH];
40 for (size_t i = 0; i < modules_count; ++i) {
41 size_t module_name_length = ::GetModuleFileNameExW(
42 process, module_handles[i], module_name, MAX_PATH);
43 if (module_name_length == 0) {
44 PLOG(ERROR) << "Failed to get module filename";
45 continue;
46 }
47 module_names->insert(std::wstring(module_name, module_name_length));
48 }
49 return true;
50 }
51
GetProcessExecutablePath(HANDLE process,std::wstring * path)52 bool GetProcessExecutablePath(HANDLE process, std::wstring* path) {
53 DCHECK(path);
54
55 std::vector<wchar_t> image_path(MAX_PATH);
56 DWORD path_length = image_path.size();
57 BOOL success =
58 ::QueryFullProcessImageName(process, 0, image_path.data(), &path_length);
59 if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
60 // Process name is potentially greater than MAX_PATH, try larger max size.
61 image_path.resize(SHRT_MAX);
62 path_length = image_path.size();
63 success = ::QueryFullProcessImageName(process, 0, image_path.data(),
64 &path_length);
65 }
66 if (!success) {
67 PLOG_IF(ERROR, ::GetLastError() != ERROR_GEN_FAILURE)
68 << "Failed to get process image path";
69 return false;
70 }
71 path->assign(image_path.data(), path_length);
72 return true;
73 }
74
GetSystemResourceUsage(HANDLE process,SystemResourceUsage * stats)75 bool GetSystemResourceUsage(HANDLE process, SystemResourceUsage* stats) {
76 DCHECK(stats);
77
78 FILETIME creation_time;
79 FILETIME exit_time;
80 FILETIME kernel_time;
81 FILETIME user_time;
82 // The returned user and kernel times are to be interpreted as time
83 // durations and not as time points. |base::Time| can convert from FILETIME
84 // to |base::Time| and by subtracting from time zero, we get the duration as
85 // a |base::TimeDelta|.
86 if (!::GetProcessTimes(process, &creation_time, &exit_time, &kernel_time,
87 &user_time)) {
88 PLOG(ERROR) << "Could not get process times";
89 return false;
90 }
91 stats->kernel_time = base::Time::FromFileTime(kernel_time) - base::Time();
92 stats->user_time = base::Time::FromFileTime(user_time) - base::Time();
93
94 std::unique_ptr<base::ProcessMetrics> metrics(
95 base::ProcessMetrics::CreateProcessMetrics(process));
96 if (!metrics || !metrics->GetIOCounters(&stats->io_counters)) {
97 LOG(ERROR) << "Failed to get IO process counters";
98 return false;
99 }
100
101 PROCESS_MEMORY_COUNTERS pmc;
102 if (::GetProcessMemoryInfo(::GetCurrentProcess(), &pmc, sizeof(pmc))) {
103 stats->peak_working_set_size = pmc.PeakWorkingSetSize;
104 }
105
106 return true;
107 }
108
109 } // namespace chrome_cleaner
110