xref: /aosp_15_r20/external/cronet/base/system/sys_info_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
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 "base/system/sys_info.h"
6 
7 #include <windows.h>
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 
12 #include <algorithm>
13 #include <bit>
14 #include <limits>
15 #include <type_traits>
16 #include <vector>
17 
18 #include "base/check.h"
19 #include "base/files/file_path.h"
20 #include "base/notreached.h"
21 #include "base/numerics/safe_conversions.h"
22 #include "base/process/process_metrics.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/strings/sys_string_conversions.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/scoped_blocking_call.h"
28 #include "base/win/registry.h"
29 #include "base/win/windows_version.h"
30 #include "third_party/abseil-cpp/absl/container/inlined_vector.h"
31 
32 namespace {
33 
34 // Returns the power efficiency levels of physical cores or empty vector on
35 // failure. The BYTE value of the element is the relative efficiency rank among
36 // all physical cores, where 0 is the most efficient, 1 is the second most
37 // efficient, and so on.
GetCoreEfficiencyClasses()38 std::vector<BYTE> GetCoreEfficiencyClasses() {
39   const DWORD kReservedSize =
40       sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) * 64;
41   absl::InlinedVector<BYTE, kReservedSize> buffer;
42   buffer.resize(kReservedSize);
43   DWORD byte_length = kReservedSize;
44   if (!GetLogicalProcessorInformationEx(
45           RelationProcessorCore,
46           reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(
47               buffer.data()),
48           &byte_length)) {
49     DPCHECK(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
50     buffer.resize(byte_length);
51     if (!GetLogicalProcessorInformationEx(
52             RelationProcessorCore,
53             reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(
54                 buffer.data()),
55             &byte_length)) {
56       return {};
57     }
58   }
59 
60   std::vector<BYTE> efficiency_classes;
61   BYTE* byte_ptr = buffer.data();
62   while (byte_ptr < buffer.data() + byte_length) {
63     const auto* structure_ptr =
64         reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*>(byte_ptr);
65     DCHECK_EQ(structure_ptr->Relationship, RelationProcessorCore);
66     DCHECK_LE(&structure_ptr->Processor.EfficiencyClass +
67                   sizeof(structure_ptr->Processor.EfficiencyClass),
68               buffer.data() + byte_length);
69     efficiency_classes.push_back(structure_ptr->Processor.EfficiencyClass);
70     DCHECK_GE(
71         structure_ptr->Size,
72         offsetof(std::remove_pointer_t<decltype(structure_ptr)>, Processor) +
73             sizeof(structure_ptr->Processor));
74     byte_ptr = byte_ptr + structure_ptr->Size;
75   }
76 
77   return efficiency_classes;
78 }
79 
80 // Returns the physical cores to logical processor mapping masks by using the
81 // Windows API GetLogicalProcessorInformation(), or an empty vector on failure.
82 // When succeeded, the vector would be of same size to the number of physical
83 // cores, while each element is the bitmask of the logical processors that the
84 // physical core has.
GetCoreProcessorMasks()85 std::vector<uint64_t> GetCoreProcessorMasks() {
86   const DWORD kReservedSize = 64;
87   absl::InlinedVector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION, kReservedSize>
88       buffer;
89   buffer.resize(kReservedSize);
90   DWORD byte_length = sizeof(buffer[0]) * kReservedSize;
91   const BOOL result =
92       GetLogicalProcessorInformation(buffer.data(), &byte_length);
93   DWORD element_count = byte_length / sizeof(buffer[0]);
94   DCHECK_EQ(byte_length % sizeof(buffer[0]), 0u);
95   if (!result) {
96     DPCHECK(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
97     buffer.resize(element_count);
98     if (!GetLogicalProcessorInformation(buffer.data(), &byte_length)) {
99       return {};
100     }
101   }
102 
103   std::vector<uint64_t> processor_masks;
104   for (DWORD i = 0; i < element_count; i++) {
105     if (buffer[i].Relationship == RelationProcessorCore) {
106       processor_masks.push_back(buffer[i].ProcessorMask);
107     }
108   }
109 
110   return processor_masks;
111 }
112 
AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field)113 uint64_t AmountOfMemory(DWORDLONG MEMORYSTATUSEX::*memory_field) {
114   MEMORYSTATUSEX memory_info;
115   memory_info.dwLength = sizeof(memory_info);
116   if (!GlobalMemoryStatusEx(&memory_info)) {
117     NOTREACHED();
118     return 0;
119   }
120 
121   return memory_info.*memory_field;
122 }
123 
GetDiskSpaceInfo(const base::FilePath & path,int64_t * available_bytes,int64_t * total_bytes)124 bool GetDiskSpaceInfo(const base::FilePath& path,
125                       int64_t* available_bytes,
126                       int64_t* total_bytes) {
127   ULARGE_INTEGER available;
128   ULARGE_INTEGER total;
129   ULARGE_INTEGER free;
130   if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
131     return false;
132 
133   if (available_bytes) {
134     *available_bytes = static_cast<int64_t>(available.QuadPart);
135     if (*available_bytes < 0)
136       *available_bytes = std::numeric_limits<int64_t>::max();
137   }
138   if (total_bytes) {
139     *total_bytes = static_cast<int64_t>(total.QuadPart);
140     if (*total_bytes < 0)
141       *total_bytes = std::numeric_limits<int64_t>::max();
142   }
143   return true;
144 }
145 
146 }  // namespace
147 
148 namespace base {
149 
150 // static
NumberOfProcessors()151 int SysInfo::NumberOfProcessors() {
152   return win::OSInfo::GetInstance()->processors();
153 }
154 
155 // static
NumberOfEfficientProcessorsImpl()156 int SysInfo::NumberOfEfficientProcessorsImpl() {
157   std::vector<BYTE> efficiency_classes = GetCoreEfficiencyClasses();
158   if (efficiency_classes.empty())
159     return 0;
160 
161   auto [min_efficiency_class_it, max_efficiency_class_it] =
162       std::minmax_element(efficiency_classes.begin(), efficiency_classes.end());
163   if (*min_efficiency_class_it == *max_efficiency_class_it)
164     return 0;
165 
166   std::vector<uint64_t> processor_masks = GetCoreProcessorMasks();
167   if (processor_masks.empty())
168     return 0;
169 
170   DCHECK_EQ(efficiency_classes.size(), processor_masks.size());
171   int num_of_efficient_processors = 0;
172   for (size_t i = 0; i < efficiency_classes.size(); i++) {
173     if (efficiency_classes[i] == *min_efficiency_class_it) {
174       num_of_efficient_processors += std::popcount(processor_masks[i]);
175     }
176   }
177 
178   return num_of_efficient_processors;
179 }
180 
181 // static
AmountOfPhysicalMemoryImpl()182 uint64_t SysInfo::AmountOfPhysicalMemoryImpl() {
183   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
184 }
185 
186 // static
AmountOfAvailablePhysicalMemoryImpl()187 uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() {
188   SystemMemoryInfoKB info;
189   if (!GetSystemMemoryInfo(&info))
190     return 0;
191   return checked_cast<uint64_t>(info.avail_phys) * 1024;
192 }
193 
194 // static
AmountOfVirtualMemory()195 uint64_t SysInfo::AmountOfVirtualMemory() {
196   return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
197 }
198 
199 // static
AmountOfFreeDiskSpace(const FilePath & path)200 int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
201   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
202                                                 base::BlockingType::MAY_BLOCK);
203 
204   int64_t available;
205   if (!GetDiskSpaceInfo(path, &available, nullptr))
206     return -1;
207   return available;
208 }
209 
210 // static
AmountOfTotalDiskSpace(const FilePath & path)211 int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) {
212   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
213                                                 base::BlockingType::MAY_BLOCK);
214 
215   int64_t total;
216   if (!GetDiskSpaceInfo(path, nullptr, &total))
217     return -1;
218   return total;
219 }
220 
OperatingSystemName()221 std::string SysInfo::OperatingSystemName() {
222   return "Windows NT";
223 }
224 
225 // static
OperatingSystemVersion()226 std::string SysInfo::OperatingSystemVersion() {
227   win::OSInfo* os_info = win::OSInfo::GetInstance();
228   win::OSInfo::VersionNumber version_number = os_info->version_number();
229   std::string version(StringPrintf("%d.%d.%d", version_number.major,
230                                    version_number.minor, version_number.build));
231   win::OSInfo::ServicePack service_pack = os_info->service_pack();
232   if (service_pack.major != 0) {
233     version += StringPrintf(" SP%d", service_pack.major);
234     if (service_pack.minor != 0)
235       version += StringPrintf(".%d", service_pack.minor);
236   }
237   return version;
238 }
239 
240 // TODO: Implement OperatingSystemVersionComplete, which would include
241 // patchlevel/service pack number.
242 // See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion.
243 
244 // static
OperatingSystemArchitecture()245 std::string SysInfo::OperatingSystemArchitecture() {
246   win::OSInfo::WindowsArchitecture arch = win::OSInfo::GetArchitecture();
247   switch (arch) {
248     case win::OSInfo::X86_ARCHITECTURE:
249       return "x86";
250     case win::OSInfo::X64_ARCHITECTURE:
251       return "x86_64";
252     case win::OSInfo::IA64_ARCHITECTURE:
253       return "ia64";
254     case win::OSInfo::ARM64_ARCHITECTURE:
255       return "arm64";
256     default:
257       return "";
258   }
259 }
260 
261 // static
CPUModelName()262 std::string SysInfo::CPUModelName() {
263   return win::OSInfo::GetInstance()->processor_model_name();
264 }
265 
266 // static
VMAllocationGranularity()267 size_t SysInfo::VMAllocationGranularity() {
268   return win::OSInfo::GetInstance()->allocation_granularity();
269 }
270 
271 // static
OperatingSystemVersionNumbers(int32_t * major_version,int32_t * minor_version,int32_t * bugfix_version)272 void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
273                                             int32_t* minor_version,
274                                             int32_t* bugfix_version) {
275   win::OSInfo* os_info = win::OSInfo::GetInstance();
276   *major_version = static_cast<int32_t>(os_info->version_number().major);
277   *minor_version = static_cast<int32_t>(os_info->version_number().minor);
278   *bugfix_version = 0;
279 }
280 
281 // static
ReadHardwareInfoFromRegistry(const wchar_t * reg_value_name)282 std::string ReadHardwareInfoFromRegistry(const wchar_t* reg_value_name) {
283   // On some systems or VMs, the system information and some of the below
284   // locations may be missing info. Attempt to find the info from the below
285   // registry keys in the order provided.
286   static const wchar_t* const kSystemInfoRegKeyPaths[] = {
287       L"HARDWARE\\DESCRIPTION\\System\\BIOS",
288       L"SYSTEM\\CurrentControlSet\\Control\\SystemInformation",
289       L"SYSTEM\\HardwareConfig\\Current",
290   };
291 
292   std::wstring value;
293   for (const wchar_t* system_info_reg_key_path : kSystemInfoRegKeyPaths) {
294     base::win::RegKey system_information_key;
295     if (system_information_key.Open(HKEY_LOCAL_MACHINE,
296                                     system_info_reg_key_path,
297                                     KEY_READ) == ERROR_SUCCESS) {
298       if ((system_information_key.ReadValue(reg_value_name, &value) ==
299            ERROR_SUCCESS) &&
300           !value.empty()) {
301         break;
302       }
303     }
304   }
305 
306   return base::SysWideToUTF8(value);
307 }
308 
309 // static
GetHardwareInfoSync()310 SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
311   HardwareInfo info = {ReadHardwareInfoFromRegistry(L"SystemManufacturer"),
312                        SysInfo::HardwareModelName()};
313   return info;
314 }
315 
316 // static
HardwareModelName()317 std::string SysInfo::HardwareModelName() {
318   return ReadHardwareInfoFromRegistry(L"SystemProductName");
319 }
320 
321 }  // namespace base
322