From c6cdd190db2a1809f0038f11a58ce675558707c7 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Tue, 22 Oct 2024 02:15:14 +0000 Subject: [PATCH] Bug 1920197 - Add prefs to allow updating Widevine directly from the Chromium update service. r=media-playback-reviewers,alwu This patch allows us to download Widevine updates directly from the Chromium update service, bypassing balrog and fallback configuration options. This will be useful in the early stages of testing Widevine updates, allowing us to use whatever Google has pushed to its own users, including beta updates, before we engage release engineering. Relevant Widevine L3 prefs have been added: - media.gmp-widevinecdm.force-chromium-update - media.gmp-widevinecdm.force-chromium-beta which force the use of the Chromium update service, and requesting beta versions (if available) respectively. Similarly, Widevine L1 prefs have been added as well: - media.gmp-widevinecdm-l1.force-chromium-update - media.gmp-widevinecdm-l1.force-chromium-beta Differential Revision: https://phabricator.services.mozilla.com/D223017 --- browser/app/profile/firefox.js | 7 ++ toolkit/modules/GMPInstallManager.sys.mjs | 114 +++++++++++++++++++--- toolkit/modules/GMPUtils.sys.mjs | 40 ++++++++ 3 files changed, 150 insertions(+), 11 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 75a0f290c49b..4f7eaec8ea65 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -2104,10 +2104,17 @@ pref("identity.fxaccounts.telemetry.clientAssociationPing.enabled", true); // unsupported. #ifdef MOZ_WIDEVINE_EME + pref("media.gmp-manager.chromium-update-url", "https://update.googleapis.com/service/update2/crx?response=redirect&x=id%3D%GUID%%26uc&acceptformat=crx3&updaterversion=999"); pref("media.gmp-widevinecdm.visible", true); pref("media.gmp-widevinecdm.enabled", true); + pref("media.gmp-widevinecdm.chromium-guid", "oimompecagnajdejgnnjijobebaeigek"); + pref("media.gmp-widevinecdm.force-chromium-update", false); + pref("media.gmp-widevinecdm.force-chromium-beta", false); #if defined(MOZ_WMF_CDM) && defined(_M_AMD64) pref("media.gmp-widevinecdm-l1.forceInstall", false); + pref("media.gmp-widevinecdm-l1.chromium-guid", "neifaoindggfcjicffkgpmnlppeffabd"); + pref("media.gmp-widevinecdm-l1.force-chromium-update", false); + pref("media.gmp-widevinecdm-l1.force-chromium-beta", false); #ifdef NIGHTLY_BUILD pref("media.gmp-widevinecdm-l1.visible", true); pref("media.gmp-widevinecdm-l1.enabled", true); diff --git a/toolkit/modules/GMPInstallManager.sys.mjs b/toolkit/modules/GMPInstallManager.sys.mjs index 32355418a1ec..5d851053f389 100644 --- a/toolkit/modules/GMPInstallManager.sys.mjs +++ b/toolkit/modules/GMPInstallManager.sys.mjs @@ -59,6 +59,27 @@ function getLocalSources() { return []; } +function redirectChromiumUpdateService(uri) { + let log = getScopedLogger("GMPInstallManager.checkForAddons"); + log.info("fetching redirect from: " + uri); + return new Promise((resolve, reject) => { + let xmlHttp = new lazy.ServiceRequest({ mozAnon: true }); + + xmlHttp.onload = function () { + resolve(this.responseURL); + }; + + xmlHttp.onerror = function (e) { + reject("Fetching " + uri + " results in error code: " + e.target.status); + }; + + xmlHttp.open("GET", uri); + xmlHttp.overrideMimeType("*/*"); + xmlHttp.setRequestHeader("Range", "bytes=0-0"); + xmlHttp.send(); + }); +} + function downloadJSON(uri) { let log = getScopedLogger("GMPInstallManager.checkForAddons"); log.info("fetching config from: " + uri); @@ -447,6 +468,72 @@ GMPInstallManager.prototype = { log.info("Failed to force addons: " + err); } + // Now let's check the addons that we are configured to override to go + // directly to the Chromium component update service. + try { + for (let gmpAddon of addons) { + if ( + !GMPPrefs.getBool( + GMPPrefs.KEY_PLUGIN_FORCE_CHROMIUM_UPDATE, + false, + gmpAddon.id + ) + ) { + continue; + } + + const guid = GMPPrefs.getString( + GMPPrefs.KEY_PLUGIN_CHROMIUM_GUID, + "", + gmpAddon.id + ); + if (guid === "") { + log.warn("Skipping chromium update, missing GUID for ", gmpAddon.id); + continue; + } + + const params = GMPUtils._getChromiumUpdateParameters(gmpAddon); + const serviceUrl = GMPPrefs.getString( + GMPPrefs.KEY_CHROMIUM_UPDATE_URL, + "" + ); + const redirectUrl = await redirectChromiumUpdateService( + serviceUrl.replace("%GUID%", guid) + params + ); + const versionMatch = redirectUrl.match(/_(\d+\.\d+\.\d+\.\d+)\//); + if (!versionMatch || versionMatch.length !== 2) { + log.warn( + "Skipping chromium update, no version from URL: ", + redirectUrl + ); + continue; + } + + const version = versionMatch[1]; + log.info( + "Forcing " + + gmpAddon.id + + " to version " + + version + + " from chromium update " + + redirectUrl + ); + + // Update the addon with the final URL and the extracted version. + gmpAddon.URL = redirectUrl; + gmpAddon.version = version; + gmpAddon.usedChromiumUpdate = true; + + // Delete these properties to avoid verifying the addon against our + // balrog configuration, which may or may not match. + delete gmpAddon.size; + delete gmpAddon.hash; + delete gmpAddon.hashFunction; + } + } catch (err) { + log.info("Failed to switch addons to Chromium update service: " + err); + } + this._deferred.resolve({ addons }); delete this._deferred; return deferredPromise; @@ -669,6 +756,7 @@ GMPInstallManager.prototype = { export function GMPAddon(addon) { let log = getScopedLogger("GMPAddon.constructor"); this.usedFallback = false; + this.usedChromiumUpdate = false; for (let name of Object.keys(addon)) { this[name] = addon[name]; } @@ -704,18 +792,18 @@ GMPAddon.prototype = { this.id && this.URL && this.version && - this.hashFunction && - !!this.hashValue + (this.usedChromiumUpdate || (this.hashFunction && !!this.hashValue)) ); }, get isInstalled() { return ( this.version && - !!this.hashValue && GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, "", this.id) === this.version && - GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_HASHVALUE, "", this.id) === - this.hashValue + (this.usedChromiumUpdate || + (!!this.hashValue && + GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_HASHVALUE, "", this.id) === + this.hashValue)) ); }, get isEME() { @@ -849,12 +937,16 @@ GMPDownloader.prototype = { log.info("Setting ABI to '" + abi + "' for " + gmpAddon.id); GMPPrefs.setString(GMPPrefs.KEY_PLUGIN_ABI, abi, gmpAddon.id); // We use the combination of the hash and version to ensure we are - // up to date. - GMPPrefs.setString( - GMPPrefs.KEY_PLUGIN_HASHVALUE, - gmpAddon.hashValue, - gmpAddon.id - ); + // up to date. Ignored if we used the Chromium update service directly. + if (!gmpAddon.usedChromiumUpdate) { + GMPPrefs.setString( + GMPPrefs.KEY_PLUGIN_HASHVALUE, + gmpAddon.hashValue, + gmpAddon.id + ); + } else { + GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_HASHVALUE, gmpAddon.id); + } // Setting the version pref signals installation completion to consumers, // if you need to set other prefs etc. do it before this. GMPPrefs.setString( diff --git a/toolkit/modules/GMPUtils.sys.mjs b/toolkit/modules/GMPUtils.sys.mjs index e2fee781e18c..0522560f4301 100644 --- a/toolkit/modules/GMPUtils.sys.mjs +++ b/toolkit/modules/GMPUtils.sys.mjs @@ -101,6 +101,42 @@ export var GMPUtils = { ); }, + _getChromiumUpdateParameters(aPlugin) { + let params = ""; + if (AppConstants.platform === "win") { + params += "&os=win"; + } else if (AppConstants.platform === "macosx") { + params += "&os=mac"; + } else if (AppConstants.platform === "linux") { + params += "&os=Linux"; + } else { + throw new Error("Unknown platform " + AppConstants.platform); + } + + const abi = Services.appinfo.XPCOMABI; + if (abi.match(/aarch64/)) { + params += "&arch=arm64&os_arch=arm64"; + } else if (abi.match(/x86_64/)) { + params += "&arch=x64&os_arch=x64"; + } else if (abi.match(/x86/)) { + params += "&arch=x86&os_arch=x86"; + } else { + throw new Error("Unknown ABI " + abi); + } + + if ( + GMPPrefs.getBool( + GMPPrefs.KEY_PLUGIN_FORCE_CHROMIUM_BETA, + false, + aPlugin.id + ) + ) { + params += "&testrequest=1"; + } + + return params; + }, + _expectedABI(aPlugin) { let defaultABI = lazy.UpdateUtils.ABI; let expectedABIs = [defaultABI]; @@ -134,9 +170,13 @@ export var GMPPrefs = { KEY_PLUGIN_FORCE_SUPPORTED: "media.{0}.forceSupported", KEY_PLUGIN_FORCE_INSTALL: "media.{0}.forceInstall", KEY_PLUGIN_ALLOW_X64_ON_ARM64: "media.{0}.allow-x64-plugin-on-arm64", + KEY_PLUGIN_CHROMIUM_GUID: "media.{0}.chromium-guid", + KEY_PLUGIN_FORCE_CHROMIUM_UPDATE: "media.{0}.force-chromium-update", + KEY_PLUGIN_FORCE_CHROMIUM_BETA: "media.{0}.force-chromium-beta", KEY_ALLOW_LOCAL_SOURCES: "media.gmp-manager.allowLocalSources", KEY_URL: "media.gmp-manager.url", KEY_URL_OVERRIDE: "media.gmp-manager.url.override", + KEY_CHROMIUM_UPDATE_URL: "media.gmp-manager.chromium-update-url", KEY_CERT_CHECKATTRS: "media.gmp-manager.cert.checkAttributes", KEY_CERT_REQUIREBUILTIN: "media.gmp-manager.cert.requireBuiltIn", KEY_CHECK_CONTENT_SIGNATURE: "media.gmp-manager.checkContentSignature",