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