Bug 2036942 - Part 1: Use the registry to get the Windows build number for telemetry and update checks. r=application-update-reviewers,TravisLong,iholmes,cdupuis

This aims to move away from using the deprecated GetVersionEx. While
this registry key isn't formally documented, it is used by Chromium for
some of their purposes (see the comments), and ultimately it usually
shouldn't be affected by compatibility shims, so updates can be pushed
regardless and telemetry can better estimate the scale of any problem.

Note that the user can override this on their system; this also fools
WinVer, giving a good suggestion that this is the 'real' value, but also
they'd need admin access. Worst-case is they get slightly different
updates and telemetry is wrong.

Differential Revision: https://phabricator.services.mozilla.com/D314482
This commit is contained in:
Duncan McIntosh
2026-08-06 01:04:24 +00:00
committed by dmcintosh@mozilla.com
parent 08b6d4ae1a
commit 183298efc4
3 changed files with 53 additions and 48 deletions
@@ -26,8 +26,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
ProfileAge: "resource://gre/modules/ProfileAge.sys.mjs",
SearchService: "moz-src:///toolkit/components/search/SearchService.sys.mjs",
WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs",
WindowsVersionInfo:
"resource://gre/modules/components-utils/WindowsVersionInfo.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "fxAccounts", () => {
@@ -1674,30 +1672,35 @@ EnvironmentCache.prototype = {
Glean.systemOs.distroVersion.set(this._osData.distroVersion);
} else if (AppConstants.platform === "win") {
// The path to the "UBR" key, queried to get additional version details on Windows.
const WINDOWS_UBR_KEY_PATH =
const CURRENT_VERSION_PATH =
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
let versionInfo = lazy.WindowsVersionInfo.get({ throwOnError: false });
this._osData.windowsBuildNumber = versionInfo.buildNumber;
Glean.systemOs.windowsBuildNumber.set(this._osData.windowsBuildNumber);
// We only need the UBR if we're at or above Windows 10.
if (
typeof this._osData.version === "string" &&
Services.vc.compare(this._osData.version, "10") >= 0
) {
// Query the UBR key and only add it to the environment if it's available.
// |readRegKey| doesn't throw, but rather returns 'undefined' on error.
let ubr = lazy.WindowsRegistry.readRegKey(
// To make sure the telemetry data is as accurate as possible, use the
// build number from the registry. This avoids a future compatibility shim
// giving us the wrong value, and we aren't changing behaviour depending
// on this so this doesn't circumvent any shim.
// See: https://randomascii.wordpress.com/2022/01/06/determinism-bugs-part-two/
// Its type is REG_SZ for some reason, so coerce it to a Number.
let build = Number(
lazy.WindowsRegistry.readRegKey(
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
WINDOWS_UBR_KEY_PATH,
"UBR",
CURRENT_VERSION_PATH,
"CurrentBuild",
Ci.nsIWindowsRegKey.WOW64_64
);
if (Number.isInteger(ubr)) {
Glean.systemOs.windowsUbr.set(ubr);
}
this._osData.windowsUBR = ubr !== undefined ? ubr : null;
}
)
);
this._osData.windowsBuildNumber = Number.isInteger(build) ? build : null;
Glean.systemOs.windowsBuildNumber.set(this._osData.windowsBuildNumber);
// The UBR value is already a REG_DWORD, so don't coerce it.
let ubr = lazy.WindowsRegistry.readRegKey(
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
CURRENT_VERSION_PATH,
"UBR",
Ci.nsIWindowsRegKey.WOW64_64
);
this._osData.windowsUBR = Number.isInteger(ubr) ? ubr : null;
Glean.systemOs.windowsUbr.set(ubr);
}
return this._osData;
+27 -25
View File
@@ -8,8 +8,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs",
WindowsVersionInfo:
"resource://gre/modules/components-utils/WindowsVersionInfo.sys.mjs",
ctypes: "resource://gre/modules/ctypes.sys.mjs",
});
@@ -1083,32 +1081,36 @@ ChromeUtils.defineLazyGetter(UpdateUtils, "OSVersion", function () {
if (osVersion) {
if (AppConstants.platform == "win") {
// Add service pack and build number
try {
const { buildNumber } = lazy.WindowsVersionInfo.get();
osVersion += `.0.0.${buildNumber}`;
} catch (err) {
console.error("Unable to retrieve windows version information: ", err);
const CURRENT_VERSION_PATH =
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
// 'CurrentBuild' is a REG_SZ for some reason, so coerce it to a number
// first.
let build = Number(
lazy.WindowsRegistry.readRegKey(
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
CURRENT_VERSION_PATH,
"CurrentBuild",
Ci.nsIWindowsRegKey.WOW64_64
)
);
if (Number.isInteger(build)) {
osVersion += `.0.0.${build}`;
} else {
osVersion += ".unknown";
}
// add UBR if on Windows 10
if (
Services.vc.compare(Services.sysinfo.getProperty("version"), "10") >= 0
) {
const WINDOWS_UBR_KEY_PATH =
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
let ubr = lazy.WindowsRegistry.readRegKey(
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
WINDOWS_UBR_KEY_PATH,
"UBR",
Ci.nsIWindowsRegKey.WOW64_64
);
if (ubr !== undefined) {
osVersion += `.${ubr}`;
} else {
osVersion += ".unknown";
}
// The value of UBR is already a REG_DWORD, so don't coerce it.
let ubr = lazy.WindowsRegistry.readRegKey(
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
CURRENT_VERSION_PATH,
"UBR",
Ci.nsIWindowsRegKey.WOW64_64
);
if (Number.isInteger(ubr)) {
osVersion += `.${ubr}`;
} else {
osVersion += ".unknown";
}
// Add processor architecture
+1 -1
View File
@@ -1435,7 +1435,7 @@ system.os:
unit: build number
lifetime: application
description: |
The Windows build number, according to WindowsVersionInfo.
The Windows build number, according to 'CurrentBuild' in the Windows registry.
Windows only.
e.g. 26100
Expected in most cases to be identical to `client_info.windows_build_number`.