From 183298efc42a57b8bbfac45fa1e6e213903b43ef Mon Sep 17 00:00:00 2001 From: Duncan McIntosh Date: Wed, 5 Aug 2026 21:55:18 +0000 Subject: [PATCH] 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 --- .../app/TelemetryEnvironment.sys.mjs | 47 +++++++++-------- toolkit/modules/UpdateUtils.sys.mjs | 52 ++++++++++--------- xpcom/metrics.yaml | 2 +- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs b/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs index c68a64346b00..e0d927b0bf27 100644 --- a/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs +++ b/toolkit/components/telemetry/app/TelemetryEnvironment.sys.mjs @@ -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; diff --git a/toolkit/modules/UpdateUtils.sys.mjs b/toolkit/modules/UpdateUtils.sys.mjs index 68a60fab0970..53af22577e90 100644 --- a/toolkit/modules/UpdateUtils.sys.mjs +++ b/toolkit/modules/UpdateUtils.sys.mjs @@ -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 diff --git a/xpcom/metrics.yaml b/xpcom/metrics.yaml index e2c0428b138e..f223bc5e2ec8 100644 --- a/xpcom/metrics.yaml +++ b/xpcom/metrics.yaml @@ -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`.