123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- // Copyright (c) 2012 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 "base/win/windows_version.h"
- #include <windows.h>
- #include <memory>
- #include <tuple>
- #include <utility>
- #include "base/check_op.h"
- #include "base/file_version_info_win.h"
- #include "base/files/file_path.h"
- #include "base/logging.h"
- #include "base/no_destructor.h"
- #include "base/notreached.h"
- #include "base/strings/string_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/win/registry.h"
- #include "build/build_config.h"
- #if !defined(__clang__) && _MSC_FULL_VER < 191125507
- #error VS 2017 Update 3.2 or higher is required
- #endif
- #if !defined(NTDDI_WIN10_FE)
- #error Windows 10.0.20348.0 SDK or higher required.
- #endif
- namespace base {
- namespace win {
- namespace {
- // The values under the CurrentVersion registry hive are mirrored under
- // the corresponding Wow6432 hive.
- constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
- L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
- // Returns the "UBR" (Windows 10 patch number) and "DisplayVersion" (or
- // "ReleaseId" on earlier versions) (Windows 10 release number) from registry.
- // "UBR" is an undocumented value and will be 0 if the value was not found.
- // "ReleaseId" will be an empty string if neither new nor old values are found.
- std::pair<int, std::string> GetVersionData() {
- DWORD ubr = 0;
- std::wstring release_id;
- RegKey key;
- if (key.Open(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion,
- KEY_QUERY_VALUE) == ERROR_SUCCESS) {
- key.ReadValueDW(L"UBR", &ubr);
- // "DisplayVersion" has been introduced in Windows 10 2009
- // when naming changed to mixed letters and numbers.
- key.ReadValue(L"DisplayVersion", &release_id);
- // Use discontinued "ReleaseId" instead, if the former is unavailable.
- if (release_id.empty())
- key.ReadValue(L"ReleaseId", &release_id);
- }
- return std::make_pair(static_cast<int>(ubr), WideToUTF8(release_id));
- }
- const _SYSTEM_INFO& GetSystemInfoStorage() {
- static const _SYSTEM_INFO system_info = [] {
- _SYSTEM_INFO info = {};
- ::GetNativeSystemInfo(&info);
- return info;
- }();
- return system_info;
- }
- } // namespace
- // static
- OSInfo** OSInfo::GetInstanceStorage() {
- // Note: we don't use the Singleton class because it depends on AtExitManager,
- // and it's convenient for other modules to use this class without it.
- static OSInfo* info = []() {
- _OSVERSIONINFOEXW version_info = {sizeof(version_info)};
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- // GetVersionEx() is deprecated, and the suggested replacement are
- // the IsWindows*OrGreater() functions in VersionHelpers.h. We can't
- // use that because:
- // - For Windows 10, there's IsWindows10OrGreater(), but nothing more
- // granular. We need to be able to detect different Windows 10 releases
- // since they sometimes change behavior in ways that matter.
- // - There is no IsWindows11OrGreater() function yet.
- ::GetVersionEx(reinterpret_cast<_OSVERSIONINFOW*>(&version_info));
- #pragma clang diagnostic pop
- DWORD os_type = 0;
- ::GetProductInfo(version_info.dwMajorVersion, version_info.dwMinorVersion,
- 0, 0, &os_type);
- return new OSInfo(version_info, GetSystemInfoStorage(), os_type);
- }();
- return &info;
- }
- // static
- OSInfo* OSInfo::GetInstance() {
- return *GetInstanceStorage();
- }
- // static
- OSInfo::WindowsArchitecture OSInfo::GetArchitecture() {
- switch (GetSystemInfoStorage().wProcessorArchitecture) {
- case PROCESSOR_ARCHITECTURE_INTEL:
- return X86_ARCHITECTURE;
- case PROCESSOR_ARCHITECTURE_AMD64:
- return X64_ARCHITECTURE;
- case PROCESSOR_ARCHITECTURE_IA64:
- return IA64_ARCHITECTURE;
- case PROCESSOR_ARCHITECTURE_ARM64:
- return ARM64_ARCHITECTURE;
- default:
- return OTHER_ARCHITECTURE;
- }
- }
- OSInfo::OSInfo(const _OSVERSIONINFOEXW& version_info,
- const _SYSTEM_INFO& system_info,
- DWORD os_type)
- : version_(Version::PRE_XP),
- wow_process_machine_(WowProcessMachine::kUnknown),
- wow_native_machine_(WowNativeMachine::kUnknown) {
- version_number_.major = version_info.dwMajorVersion;
- version_number_.minor = version_info.dwMinorVersion;
- version_number_.build = version_info.dwBuildNumber;
- std::tie(version_number_.patch, release_id_) = GetVersionData();
- version_ = MajorMinorBuildToVersion(
- version_number_.major, version_number_.minor, version_number_.build);
- InitializeWowStatusValuesForProcess(GetCurrentProcess());
- service_pack_.major = version_info.wServicePackMajor;
- service_pack_.minor = version_info.wServicePackMinor;
- service_pack_str_ = WideToUTF8(version_info.szCSDVersion);
- processors_ = static_cast<int>(system_info.dwNumberOfProcessors);
- allocation_granularity_ = system_info.dwAllocationGranularity;
- if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
- // Only present on Vista+.
- switch (os_type) {
- case PRODUCT_CLUSTER_SERVER:
- case PRODUCT_DATACENTER_SERVER:
- case PRODUCT_DATACENTER_SERVER_CORE:
- case PRODUCT_ENTERPRISE_SERVER:
- case PRODUCT_ENTERPRISE_SERVER_CORE:
- case PRODUCT_ENTERPRISE_SERVER_IA64:
- case PRODUCT_SMALLBUSINESS_SERVER:
- case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
- case PRODUCT_STANDARD_SERVER:
- case PRODUCT_STANDARD_SERVER_CORE:
- case PRODUCT_WEB_SERVER:
- version_type_ = SUITE_SERVER;
- break;
- case PRODUCT_PROFESSIONAL:
- case PRODUCT_ULTIMATE:
- version_type_ = SUITE_PROFESSIONAL;
- break;
- case PRODUCT_ENTERPRISE:
- case PRODUCT_ENTERPRISE_E:
- case PRODUCT_ENTERPRISE_EVALUATION:
- case PRODUCT_ENTERPRISE_N:
- case PRODUCT_ENTERPRISE_N_EVALUATION:
- case PRODUCT_ENTERPRISE_S:
- case PRODUCT_ENTERPRISE_S_EVALUATION:
- case PRODUCT_ENTERPRISE_S_N:
- case PRODUCT_ENTERPRISE_S_N_EVALUATION:
- case PRODUCT_BUSINESS:
- case PRODUCT_BUSINESS_N:
- version_type_ = SUITE_ENTERPRISE;
- break;
- case PRODUCT_PRO_FOR_EDUCATION:
- case PRODUCT_PRO_FOR_EDUCATION_N:
- version_type_ = SUITE_EDUCATION_PRO;
- break;
- case PRODUCT_EDUCATION:
- case PRODUCT_EDUCATION_N:
- version_type_ = SUITE_EDUCATION;
- break;
- case PRODUCT_HOME_BASIC:
- case PRODUCT_HOME_PREMIUM:
- case PRODUCT_STARTER:
- default:
- version_type_ = SUITE_HOME;
- break;
- }
- } else if (version_info.dwMajorVersion == 5 &&
- version_info.dwMinorVersion == 2) {
- if (version_info.wProductType == VER_NT_WORKSTATION &&
- system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
- version_type_ = SUITE_PROFESSIONAL;
- } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER) {
- version_type_ = SUITE_HOME;
- } else {
- version_type_ = SUITE_SERVER;
- }
- } else if (version_info.dwMajorVersion == 5 &&
- version_info.dwMinorVersion == 1) {
- if (version_info.wSuiteMask & VER_SUITE_PERSONAL)
- version_type_ = SUITE_HOME;
- else
- version_type_ = SUITE_PROFESSIONAL;
- } else {
- // Windows is pre XP so we don't care but pick a safe default.
- version_type_ = SUITE_HOME;
- }
- }
- OSInfo::~OSInfo() = default;
- Version OSInfo::Kernel32Version() const {
- static const Version kernel32_version =
- MajorMinorBuildToVersion(Kernel32BaseVersion().components()[0],
- Kernel32BaseVersion().components()[1],
- Kernel32BaseVersion().components()[2]);
- return kernel32_version;
- }
- OSInfo::VersionNumber OSInfo::Kernel32VersionNumber() const {
- DCHECK_EQ(Kernel32BaseVersion().components().size(), 4u);
- static const VersionNumber version = {
- .major = Kernel32BaseVersion().components()[0],
- .minor = Kernel32BaseVersion().components()[1],
- .build = Kernel32BaseVersion().components()[2],
- .patch = Kernel32BaseVersion().components()[3]};
- return version;
- }
- // Retrieve a version from kernel32. This is useful because when running in
- // compatibility mode for a down-level version of the OS, the file version of
- // kernel32 will still be the "real" version.
- base::Version OSInfo::Kernel32BaseVersion() const {
- static const NoDestructor<base::Version> version([] {
- std::unique_ptr<FileVersionInfoWin> file_version_info =
- FileVersionInfoWin::CreateFileVersionInfoWin(
- FilePath(FILE_PATH_LITERAL("kernel32.dll")));
- if (!file_version_info) {
- // crbug.com/912061: on some systems it seems kernel32.dll might be
- // corrupted or not in a state to get version info. In this case try
- // kernelbase.dll as a fallback.
- file_version_info = FileVersionInfoWin::CreateFileVersionInfoWin(
- FilePath(FILE_PATH_LITERAL("kernelbase.dll")));
- }
- CHECK(file_version_info);
- return file_version_info->GetFileVersion();
- }());
- return *version;
- }
- bool OSInfo::IsWowDisabled() const {
- return (wow_process_machine_ == WowProcessMachine::kDisabled);
- }
- bool OSInfo::IsWowX86OnAMD64() const {
- return (wow_process_machine_ == WowProcessMachine::kX86 &&
- wow_native_machine_ == WowNativeMachine::kAMD64);
- }
- bool OSInfo::IsWowX86OnARM64() const {
- return (wow_process_machine_ == WowProcessMachine::kX86 &&
- wow_native_machine_ == WowNativeMachine::kARM64);
- }
- bool OSInfo::IsWowAMD64OnARM64() const {
- #if defined(ARCH_CPU_X86_64)
- // An AMD64 process running on an ARM64 device results in the incorrect
- // identification of the device architecture (AMD64 is reported). However,
- // IsWow64Process2 will return the correct device type for the native
- // machine, even though the OS doesn't consider an AMD64 process on an ARM64
- // processor a classic Windows-on-Windows setup.
- return (wow_process_machine_ == WowProcessMachine::kDisabled &&
- wow_native_machine_ == WowNativeMachine::kARM64);
- #else
- return false;
- #endif
- }
- bool OSInfo::IsWowX86OnOther() const {
- return (wow_process_machine_ == WowProcessMachine::kX86 &&
- wow_native_machine_ == WowNativeMachine::kOther);
- }
- std::string OSInfo::processor_model_name() {
- if (processor_model_name_.empty()) {
- const wchar_t kProcessorNameString[] =
- L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
- RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
- std::wstring value;
- key.ReadValue(L"ProcessorNameString", &value);
- processor_model_name_ = WideToUTF8(value);
- }
- return processor_model_name_;
- }
- // With the exception of Server 2003, server variants are treated the same as
- // the corresponding workstation release.
- // static
- Version OSInfo::MajorMinorBuildToVersion(uint32_t major,
- uint32_t minor,
- uint32_t build) {
- if (major == 11)
- return Version::WIN11;
- if (major == 10) {
- if (build >= 22000)
- return Version::WIN11;
- if (build >= 20348)
- return Version::SERVER_2022;
- if (build >= 19044)
- return Version::WIN10_21H2;
- if (build >= 19043)
- return Version::WIN10_21H1;
- if (build >= 19042)
- return Version::WIN10_20H2;
- if (build >= 19041)
- return Version::WIN10_20H1;
- if (build >= 18363)
- return Version::WIN10_19H2;
- if (build >= 18362)
- return Version::WIN10_19H1;
- if (build >= 17763)
- return Version::WIN10_RS5;
- if (build >= 17134)
- return Version::WIN10_RS4;
- if (build >= 16299)
- return Version::WIN10_RS3;
- if (build >= 15063)
- return Version::WIN10_RS2;
- if (build >= 14393)
- return Version::WIN10_RS1;
- if (build >= 10586)
- return Version::WIN10_TH2;
- return Version::WIN10;
- }
- if (major > 6) {
- // Hitting this likely means that it's time for a >11 block above.
- NOTREACHED() << major << "." << minor << "." << build;
- return Version::WIN_LAST;
- }
- if (major == 6) {
- switch (minor) {
- case 0:
- return Version::VISTA;
- case 1:
- return Version::WIN7;
- case 2:
- return Version::WIN8;
- default:
- DCHECK_EQ(minor, 3u);
- return Version::WIN8_1;
- }
- }
- if (major == 5 && minor != 0) {
- // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
- return minor == 1 ? Version::XP : Version::SERVER_2003;
- }
- // Win 2000 or older.
- return Version::PRE_XP;
- }
- Version GetVersion() {
- return OSInfo::GetInstance()->version();
- }
- OSInfo::WowProcessMachine OSInfo::GetWowProcessMachineArchitecture(
- const int process_machine) {
- switch (process_machine) {
- case IMAGE_FILE_MACHINE_UNKNOWN:
- return OSInfo::WowProcessMachine::kDisabled;
- case IMAGE_FILE_MACHINE_I386:
- return OSInfo::WowProcessMachine::kX86;
- case IMAGE_FILE_MACHINE_ARM:
- case IMAGE_FILE_MACHINE_THUMB:
- case IMAGE_FILE_MACHINE_ARMNT:
- return OSInfo::WowProcessMachine::kARM32;
- }
- return OSInfo::WowProcessMachine::kOther;
- }
- OSInfo::WowNativeMachine OSInfo::GetWowNativeMachineArchitecture(
- const int native_machine) {
- switch (native_machine) {
- case IMAGE_FILE_MACHINE_ARM64:
- return OSInfo::WowNativeMachine::kARM64;
- case IMAGE_FILE_MACHINE_AMD64:
- return OSInfo::WowNativeMachine::kAMD64;
- }
- return OSInfo::WowNativeMachine::kOther;
- }
- void OSInfo::InitializeWowStatusValuesFromLegacyApi(HANDLE process_handle) {
- BOOL is_wow64 = FALSE;
- if (!::IsWow64Process(process_handle, &is_wow64))
- return;
- if (is_wow64) {
- wow_process_machine_ = WowProcessMachine::kX86;
- wow_native_machine_ = WowNativeMachine::kAMD64;
- } else {
- wow_process_machine_ = WowProcessMachine::kDisabled;
- }
- }
- void OSInfo::InitializeWowStatusValuesForProcess(HANDLE process_handle) {
- static const auto is_wow64_process2 =
- reinterpret_cast<decltype(&IsWow64Process2)>(::GetProcAddress(
- ::GetModuleHandle(L"kernel32.dll"), "IsWow64Process2"));
- if (!is_wow64_process2) {
- InitializeWowStatusValuesFromLegacyApi(process_handle);
- return;
- }
- USHORT process_machine = IMAGE_FILE_MACHINE_UNKNOWN;
- USHORT native_machine = IMAGE_FILE_MACHINE_UNKNOWN;
- if (!is_wow64_process2(process_handle, &process_machine, &native_machine)) {
- return;
- }
- wow_process_machine_ = GetWowProcessMachineArchitecture(process_machine);
- wow_native_machine_ = GetWowNativeMachineArchitecture(native_machine);
- }
- } // namespace win
- } // namespace base
|