Skip to content

Commit

Permalink
Add histograms to compare GetVersionEx() with VerQueryValue() of kern…
Browse files Browse the repository at this point in the history
…el32

Checking VerQueryValue() of kernel32 reports the "real" OS, rather than
the potentially shimmed one that GetVersionEx() reports.

Normally it's better to use GetVersionEx() because that'll determine the
APIs that are available and how they behave. However, we'd like to know
if there are a substantial percentage of users in compatibility mode, as
there have been complaints of users seeing the "XP and Vista are no
longer supported" infobar on Windows 7.

[email protected], [email protected], [email protected], [email protected]
BUG=581499

Review URL: https://codereview.chromium.org/1784623003

Cr-Commit-Position: refs/heads/master@{#380793}
(cherry picked from commit d68b1e1)

Review URL: https://codereview.chromium.org/1797073003 .

Cr-Commit-Position: refs/branch-heads/2661@{crosswalk-project#233}
Cr-Branched-From: ef6f6ae-refs/heads/master@{#378081}
  • Loading branch information
sgraham committed Mar 15, 2016
1 parent 58803ba commit d687065
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 42 deletions.
1 change: 1 addition & 0 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,7 @@ test("base_unittests") {
"win/shortcut_unittest.cc",
"win/startup_information_unittest.cc",
"win/win_util_unittest.cc",
"win/windows_version_unittest.cc",
"win/wrapped_window_proc_unittest.cc",
]

Expand Down
1 change: 1 addition & 0 deletions base/base.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@
'win/shortcut_unittest.cc',
'win/startup_information_unittest.cc',
'win/win_util_unittest.cc',
'win/windows_version_unittest.cc',
'win/wrapped_window_proc_unittest.cc',
'<@(trace_event_test_sources)',
],
Expand Down
110 changes: 77 additions & 33 deletions base/win/windows_version.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,81 @@

#include <windows.h>

#include "base/file_version_info_win.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"

namespace {
typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
}
} // namespace

namespace base {
namespace win {

namespace {

// Helper to map a major.minor.x.build version (e.g. 6.1) to a Windows release.
Version MajorMinorBuildToVersion(int major, int minor, int build) {
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;
} else if (major == 6) {
switch (minor) {
case 0:
// Treat Windows Server 2008 the same as Windows Vista.
return VERSION_VISTA;
case 1:
// Treat Windows Server 2008 R2 the same as Windows 7.
return VERSION_WIN7;
case 2:
// Treat Windows Server 2012 the same as Windows 8.
return VERSION_WIN8;
default:
DCHECK_EQ(minor, 3);
return VERSION_WIN8_1;
}
} else if (major == 10) {
if (build < 10586) {
return VERSION_WIN10;
} else {
return VERSION_WIN10_TH2;
}
} else if (major > 6) {
NOTREACHED();
return VERSION_WIN_LAST;
}

NOTREACHED();
return VERSION_WIN_LAST;
}

// 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.
Version GetVersionFromKernel32() {
scoped_ptr<FileVersionInfoWin> file_version_info(
static_cast<FileVersionInfoWin*>(
FileVersionInfoWin::CreateFileVersionInfo(
base::FilePath(FILE_PATH_LITERAL("kernel32.dll")))));
if (file_version_info) {
const int major =
HIWORD(file_version_info->fixed_file_info()->dwFileVersionMS);
const int minor =
LOWORD(file_version_info->fixed_file_info()->dwFileVersionMS);
const int build =
HIWORD(file_version_info->fixed_file_info()->dwFileVersionLS);
return MajorMinorBuildToVersion(major, minor, build);
}

NOTREACHED();
return VERSION_WIN_LAST;
}

} // namespace

// static
OSInfo* OSInfo::GetInstance() {
// Note: we don't use the Singleton class because it depends on AtExitManager,
Expand All @@ -35,45 +99,17 @@ OSInfo* OSInfo::GetInstance() {

OSInfo::OSInfo()
: version_(VERSION_PRE_XP),
kernel32_version_(VERSION_PRE_XP),
got_kernel32_version_(false),
architecture_(OTHER_ARCHITECTURE),
wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
OSVERSIONINFOEX version_info = { sizeof version_info };
::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
version_number_.major = version_info.dwMajorVersion;
version_number_.minor = version_info.dwMinorVersion;
version_number_.build = version_info.dwBuildNumber;
if ((version_number_.major == 5) && (version_number_.minor > 0)) {
// Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003;
} else if (version_number_.major == 6) {
switch (version_number_.minor) {
case 0:
// Treat Windows Server 2008 the same as Windows Vista.
version_ = VERSION_VISTA;
break;
case 1:
// Treat Windows Server 2008 R2 the same as Windows 7.
version_ = VERSION_WIN7;
break;
case 2:
// Treat Windows Server 2012 the same as Windows 8.
version_ = VERSION_WIN8;
break;
default:
DCHECK_EQ(version_number_.minor, 3);
version_ = VERSION_WIN8_1;
break;
}
} else if (version_number_.major == 10) {
if (version_number_.build < 10586) {
version_ = VERSION_WIN10;
} else {
version_ = VERSION_WIN10_TH2;
}
} else if (version_number_.major > 6) {
NOTREACHED();
version_ = VERSION_WIN_LAST;
}
version_ = MajorMinorBuildToVersion(
version_number_.major, version_number_.minor, version_number_.build);
service_pack_.major = version_info.wServicePackMajor;
service_pack_.minor = version_info.wServicePackMinor;

Expand Down Expand Up @@ -149,6 +185,14 @@ OSInfo::OSInfo()
OSInfo::~OSInfo() {
}

Version OSInfo::Kernel32Version() const {
if (!got_kernel32_version_) {
kernel32_version_ = GetVersionFromKernel32();
got_kernel32_version_ = true;
}
return kernel32_version_;
}

std::string OSInfo::processor_model_name() {
if (processor_model_name_.empty()) {
const wchar_t kProcessorNameString[] =
Expand Down
24 changes: 15 additions & 9 deletions base/win/windows_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@ namespace win {
// syntactic sugar reasons; see the declaration of GetVersion() below.
// NOTE: Keep these in order so callers can do things like
// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...".
//
// This enum is used in metrics histograms, so they shouldn't be reordered or
// removed. New values can be added before VERSION_WIN_LAST.
enum Version {
VERSION_PRE_XP = 0, // Not supported.
VERSION_XP,
VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
VERSION_VISTA, // Also includes Windows Server 2008.
VERSION_WIN7, // Also includes Windows Server 2008 R2.
VERSION_WIN8, // Also includes Windows Server 2012.
VERSION_WIN8_1, // Also includes Windows Server 2012 R2.
VERSION_WIN10, // Also includes Windows 10 Server.
VERSION_WIN10_TH2, // Threshold 2: Version 1511, Build 10586.
VERSION_WIN_LAST, // Indicates error condition.
VERSION_XP = 1,
VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2.
VERSION_VISTA = 3, // Also includes Windows Server 2008.
VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2.
VERSION_WIN8 = 5, // Also includes Windows Server 2012.
VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2.
VERSION_WIN10 = 7, // Also includes Windows 10 Server.
VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586.
VERSION_WIN_LAST, // Indicates error condition.
};

// A rough bucketing of the available types of versions of Windows. This is used
Expand Down Expand Up @@ -86,6 +89,7 @@ class BASE_EXPORT OSInfo {
static OSInfo* GetInstance();

Version version() const { return version_; }
Version Kernel32Version() const;
// The next two functions return arrays of values, [major, minor(, build)].
VersionNumber version_number() const { return version_number_; }
VersionType version_type() const { return version_type_; }
Expand All @@ -105,6 +109,8 @@ class BASE_EXPORT OSInfo {
~OSInfo();

Version version_;
mutable Version kernel32_version_;
mutable bool got_kernel32_version_;
VersionNumber version_number_;
VersionType version_type_;
ServicePack service_pack_;
Expand Down
22 changes: 22 additions & 0 deletions base/win/windows_version_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2016 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 "testing/gtest/include/gtest/gtest.h"

namespace base {
namespace win {
namespace {

TEST(WindowsVersion, GetVersionExAndKernelVersionMatch) {
// If this fails, we're running in compatibility mode, or need to update the
// application manifest.
EXPECT_EQ(OSInfo::GetInstance()->version(),
OSInfo::GetInstance()->Kernel32Version());
}

} // namespace
} // namespace win
} // namespace base
10 changes: 10 additions & 0 deletions chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#endif // defined(USE_OZONE) || defined(USE_X11)

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "chrome/installer/util/google_update_settings.h"
#endif // defined(OS_WIN)

Expand Down Expand Up @@ -140,6 +141,15 @@ void RecordMicroArchitectureStats() {
void RecordStartupMetricsOnBlockingPool() {
#if defined(OS_WIN)
GoogleUpdateSettings::RecordChromeUpdatePolicyHistograms();

const base::win::OSInfo& os_info = *base::win::OSInfo::GetInstance();
UMA_HISTOGRAM_ENUMERATION("Windows.GetVersionExVersion", os_info.version(),
base::win::VERSION_WIN_LAST);
UMA_HISTOGRAM_ENUMERATION("Windows.Kernel32Version",
os_info.Kernel32Version(),
base::win::VERSION_WIN_LAST);
UMA_HISTOGRAM_BOOLEAN("Windows.InCompatibilityMode",
os_info.version() != os_info.Kernel32Version());
#endif // defined(OS_WIN)

#if defined(OS_MACOSX)
Expand Down
33 changes: 33 additions & 0 deletions tools/metrics/histograms/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57956,6 +57956,31 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary>
</histogram>

<histogram name="Windows.GetVersionExVersion" enum="WindowsVersion">
<owner>[email protected]</owner>
<summary>
The Windows version (base::win::Version) as reported by GetVersionEx(). This
is queried shortly after startup.
</summary>
</histogram>

<histogram name="Windows.InCompatibilityMode" enum="BooleanCompatibilityMode">
<owner>[email protected]</owner>
<summary>
A boolean used to indicate when the Windows version reported by
GetVersionEx() and the Windows version reported by VerQueryValue() on
kernel32 do not match. This is queried shortly after startup.
</summary>
</histogram>

<histogram name="Windows.Kernel32Version" enum="WindowsVersion">
<owner>[email protected]</owner>
<summary>
The Windows version (base::win::Version) as reported by VeryQueryValue() on
kernel32.dll. This is queried shortly after startup.
</summary>
</histogram>

<histogram name="Windows.Tablet" enum="BooleanTablet">
<owner>[email protected]</owner>
<summary>Count of browser launches from a Windows tablet pc.</summary>
Expand Down Expand Up @@ -59633,6 +59658,11 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<int value="1" label="Common Name used"/>
</enum>

<enum name="BooleanCompatibilityMode" type="int">
<int value="0" label="Not in compatibility mode"/>
<int value="1" label="In compatibility mode"/>
</enum>

<enum name="BooleanCompleted" type="int">
<int value="0" label="Not Completed"/>
<int value="1" label="Completed"/>
Expand Down Expand Up @@ -83515,6 +83545,9 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="3" label="Vista"/>
<int value="4" label="Windows 7"/>
<int value="5" label="Windows 8"/>
<int value="6" label="Windows 8.1"/>
<int value="7" label="Windows 10"/>
<int value="8" label="Windows 10 TH2"/>
</enum>

<enum name="WindowType" type="int">
Expand Down

0 comments on commit d687065

Please sign in to comment.