mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 1920197 - Add prefs to allow updating Widevine directly from the Chromium update service. a=dmeehan
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. Original Revision: https://phabricator.services.mozilla.com/D223017 Differential Revision: https://phabricator.services.mozilla.com/D227283
This commit is contained in:
parent
b50bec4f89
commit
6c929b3dbc
@ -1822,8 +1822,12 @@ pref("media.gmp.trial-create.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);
|
||||
#endif
|
||||
|
||||
pref("media.gmp-gmpopenh264.visible", true);
|
||||
|
@ -53,6 +53,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);
|
||||
@ -332,6 +353,7 @@ GMPInstallManager.prototype = {
|
||||
}
|
||||
|
||||
this._deferred = PromiseUtils.defer();
|
||||
let deferredPromise = this._deferred.promise;
|
||||
|
||||
// Should content signature checking of Balrog replies be used? If so this
|
||||
// will be done instead of the older cert pinning method.
|
||||
@ -363,46 +385,131 @@ GMPInstallManager.prototype = {
|
||||
log.info(
|
||||
`Fetching product addon list url=${url}, allowNonBuiltIn=${allowNonBuiltIn}, certs=${certs}, checkContentSignature=${checkContentSignature}, trustedContentSignatureRoot=${trustedContentSignatureRoot}`
|
||||
);
|
||||
let addonPromise = ProductAddonChecker.getProductAddonList(
|
||||
url,
|
||||
allowNonBuiltIn,
|
||||
certs,
|
||||
checkContentSignature,
|
||||
trustedContentSignatureRoot
|
||||
)
|
||||
.then(res => {
|
||||
if (checkContentSignature) {
|
||||
this.recordUpdateXmlTelemetryForContentSignature(true);
|
||||
} else {
|
||||
this.recordUpdateXmlTelemetryForCertPinning(true);
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch(err => {
|
||||
if (checkContentSignature) {
|
||||
this.recordUpdateXmlTelemetryForContentSignature(false, err);
|
||||
} else {
|
||||
this.recordUpdateXmlTelemetryForCertPinning(false, err);
|
||||
}
|
||||
return downloadLocalConfig();
|
||||
});
|
||||
|
||||
addonPromise.then(
|
||||
res => {
|
||||
if (!res || !res.addons) {
|
||||
this._deferred.resolve({ addons: [] });
|
||||
} else {
|
||||
res.addons = res.addons.map(a => new GMPAddon(a));
|
||||
this._deferred.resolve(res);
|
||||
}
|
||||
delete this._deferred;
|
||||
},
|
||||
ex => {
|
||||
this._deferred.reject(ex);
|
||||
delete this._deferred;
|
||||
let success = true;
|
||||
let res;
|
||||
try {
|
||||
res = await ProductAddonChecker.getProductAddonList(
|
||||
url,
|
||||
allowNonBuiltIn,
|
||||
certs,
|
||||
checkContentSignature,
|
||||
trustedContentSignatureRoot
|
||||
);
|
||||
|
||||
if (checkContentSignature) {
|
||||
this.recordUpdateXmlTelemetryForContentSignature(true);
|
||||
} else {
|
||||
this.recordUpdateXmlTelemetryForCertPinning(true);
|
||||
}
|
||||
);
|
||||
return this._deferred.promise;
|
||||
} catch (err) {
|
||||
success = false;
|
||||
if (checkContentSignature) {
|
||||
this.recordUpdateXmlTelemetryForContentSignature(false, err);
|
||||
} else {
|
||||
this.recordUpdateXmlTelemetryForCertPinning(false, err);
|
||||
}
|
||||
}
|
||||
|
||||
let localSources = getLocalSources();
|
||||
|
||||
try {
|
||||
if (!success) {
|
||||
log.info("Falling back to local config");
|
||||
let fallbackSources = localSources.filter(function (gmpSource) {
|
||||
return gmpSource.installByDefault;
|
||||
});
|
||||
res = await downloadLocalConfig(fallbackSources);
|
||||
}
|
||||
} catch (err) {
|
||||
this._deferred.reject(err);
|
||||
delete this._deferred;
|
||||
return deferredPromise;
|
||||
}
|
||||
|
||||
let addons;
|
||||
if (res && res.addons) {
|
||||
addons = res.addons.map(a => new GMPAddon(a));
|
||||
} else {
|
||||
addons = [];
|
||||
}
|
||||
|
||||
let usedFallback;
|
||||
if (res && res.usedFallback !== undefined) {
|
||||
usedFallback = res.usedFallback;
|
||||
} else {
|
||||
usedFallback = true;
|
||||
}
|
||||
|
||||
// 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({ usedFallback, addons });
|
||||
delete this._deferred;
|
||||
return deferredPromise;
|
||||
},
|
||||
/**
|
||||
* Installs the specified addon and calls a callback when done.
|
||||
@ -621,6 +728,7 @@ GMPInstallManager.prototype = {
|
||||
*/
|
||||
export function GMPAddon(addon) {
|
||||
let log = getScopedLogger("GMPAddon.constructor");
|
||||
this.usedChromiumUpdate = false;
|
||||
for (let name of Object.keys(addon)) {
|
||||
this[name] = addon[name];
|
||||
}
|
||||
@ -656,18 +764,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() {
|
||||
@ -783,48 +891,66 @@ GMPDownloader.prototype = {
|
||||
gmpAddon.version,
|
||||
]);
|
||||
let installPromise = gmpInstaller.install();
|
||||
return installPromise.then(
|
||||
extractedPaths => {
|
||||
// Success, set the prefs
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
GMPPrefs.setInt(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, now, gmpAddon.id);
|
||||
// Remember our ABI, so that if the profile is migrated to another
|
||||
// platform or from 32 -> 64 bit, we notice and don't try to load the
|
||||
// unexecutable plugin library.
|
||||
let abi = GMPUtils._expectedABI(gmpAddon);
|
||||
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
|
||||
);
|
||||
// Setting the version pref signals installation completion to consumers,
|
||||
// if you need to set other prefs etc. do it before this.
|
||||
GMPPrefs.setString(
|
||||
GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
gmpAddon.version,
|
||||
gmpAddon.id
|
||||
);
|
||||
return extractedPaths;
|
||||
},
|
||||
reason => {
|
||||
GMPPrefs.setString(
|
||||
GMPPrefs.KEY_PLUGIN_LAST_INSTALL_FAIL_REASON,
|
||||
reason,
|
||||
gmpAddon.id
|
||||
);
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
GMPPrefs.setInt(
|
||||
GMPPrefs.KEY_PLUGIN_LAST_INSTALL_FAILED,
|
||||
now,
|
||||
gmpAddon.id
|
||||
);
|
||||
throw reason;
|
||||
}
|
||||
);
|
||||
return installPromise
|
||||
.then(
|
||||
extractedPaths => {
|
||||
// Success, set the prefs
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
GMPPrefs.setInt(
|
||||
GMPPrefs.KEY_PLUGIN_LAST_UPDATE,
|
||||
now,
|
||||
gmpAddon.id
|
||||
);
|
||||
// Remember our ABI, so that if the profile is migrated to another
|
||||
// platform or from 32 -> 64 bit, we notice and don't try to load the
|
||||
// unexecutable plugin library.
|
||||
let abi = GMPUtils._expectedABI(gmpAddon);
|
||||
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. 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(
|
||||
GMPPrefs.KEY_PLUGIN_VERSION,
|
||||
gmpAddon.version,
|
||||
gmpAddon.id
|
||||
);
|
||||
return extractedPaths;
|
||||
},
|
||||
reason => {
|
||||
GMPPrefs.setString(
|
||||
GMPPrefs.KEY_PLUGIN_LAST_INSTALL_FAIL_REASON,
|
||||
reason,
|
||||
gmpAddon.id
|
||||
);
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
GMPPrefs.setInt(
|
||||
GMPPrefs.KEY_PLUGIN_LAST_INSTALL_FAILED,
|
||||
now,
|
||||
gmpAddon.id
|
||||
);
|
||||
throw reason;
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
log.info(`Deleting ${gmpAddon.id} temporary zip file ${zipPath}`);
|
||||
// We need to send out an observer event to ensure the nsZipReaderCache
|
||||
// clears its cache entries associated with our temporary file. Otherwise
|
||||
// if the addons downloader reuses the temporary file path, then we may hit
|
||||
// the cache and get different contents than expected.
|
||||
Services.obs.notifyObservers(null, "flush-cache-entry", zipPath);
|
||||
IOUtils.remove(zipPath);
|
||||
});
|
||||
},
|
||||
reason => {
|
||||
GMPPrefs.setString(
|
||||
|
@ -92,6 +92,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];
|
||||
@ -124,9 +160,13 @@ export var GMPPrefs = {
|
||||
KEY_PLUGIN_ABI: "media.{0}.abi",
|
||||
KEY_PLUGIN_FORCE_SUPPORTED: "media.{0}.forceSupported",
|
||||
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",
|
||||
|
Loading…
Reference in New Issue
Block a user