author | Andreea Pavel <apavel@mozilla.com> |
Tue, 24 Apr 2018 04:35:07 +0300 | |
changeset 468715 | 60cf97933726a504197477aab9f8092cf9fd97b5 |
parent 468714 | 1e3173e0ad058647182f3aa2d94b03b30eb0fe4f |
child 468716 | f63f20404c553366c4724be5b9690b755f7712ef |
push id | 9165 |
push user | asasaki@mozilla.com |
push date | Thu, 26 Apr 2018 21:04:54 +0000 |
treeherder | mozilla-beta@064c3804de2e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1433574 |
milestone | 61.0a1 |
backs out | cf1022433399232d089891e4979fced0289b0e7c |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -194,16 +194,17 @@ pref("extensions.enabledScopes", 1); pref("extensions.autoupdate.enabled", true); pref("extensions.autoupdate.interval", 86400); pref("extensions.update.enabled", true); pref("extensions.update.interval", 86400); pref("extensions.dss.enabled", false); pref("extensions.ignoreMTimeChanges", false); pref("extensions.logging.enabled", false); pref("extensions.hideInstallButton", true); +pref("extensions.showMismatchUI", false); pref("extensions.hideUpdateButton", false); pref("extensions.strictCompatibility", false); pref("extensions.minCompatibleAppVersion", "11.0"); pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); pref("extensions.update.background.url", "https://versioncheck-bg.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%¤tAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%"); /* preferences for the Get Add-ons pane */
--- a/testing/geckodriver/src/prefs.rs +++ b/testing/geckodriver/src/prefs.rs @@ -153,16 +153,18 @@ lazy_static! { // Disable intalling any distribution extensions or add-ons ("extensions.installDistroAddons", Pref::new(false)), // Make sure Shield doesn't hit the network. // Removed in Firefox 60. ("extensions.shield-recipe-client.api_url", Pref::new("")), + ("extensions.showMismatchUI", Pref::new(false)), + // Turn off extension updates so they do not bother tests ("extensions.update.enabled", Pref::new(false)), ("extensions.update.notifyUser", Pref::new(false)), // Make sure opening about:addons will not hit the network ("extensions.webservice.discoverURL", Pref::new("http://%(server)s/dummy/discoveryURL")), // Allow the application to have focus even it runs in the
--- a/testing/marionette/client/marionette_driver/geckoinstance.py +++ b/testing/marionette/client/marionette_driver/geckoinstance.py @@ -63,16 +63,17 @@ class GeckoInstance(object): "extensions.enabledScopes": 5, # Disable metadata caching for installed add-ons by default "extensions.getAddons.cache.enabled": False, # Disable intalling any distribution add-ons "extensions.installDistroAddons": False, # Make sure Shield doesn't hit the network. # Removed in Firefox 60. "extensions.shield-recipe-client.api_url": "", + "extensions.showMismatchUI": False, # Turn off extension updates so they don't bother tests "extensions.update.enabled": False, "extensions.update.notifyUser": False, # Make sure opening about:addons won"t hit the network "extensions.webservice.discoverURL": "http://%(server)s/dummy/discoveryURL", # Allow the application to have focus even it runs in the background "focusmanager.testmode": True,
--- a/testing/marionette/components/marionette.js +++ b/testing/marionette/components/marionette.js @@ -192,16 +192,18 @@ const RECOMMENDED_PREFS = new Map([ // Disable metadata caching for installed add-ons by default ["extensions.getAddons.cache.enabled", false], // Disable installing any distribution extensions or add-ons. // Should be set in profile. ["extensions.installDistroAddons", false], + ["extensions.showMismatchUI", false], + // Turn off extension updates so they do not bother tests ["extensions.update.enabled", false], ["extensions.update.notifyUser", false], // Make sure opening about:addons will not hit the network [ "extensions.webservice.discoverURL", "http://%(server)s/dummy/discoveryURL",
--- a/testing/mozbase/mozprofile/mozprofile/profile.py +++ b/testing/mozbase/mozprofile/mozprofile/profile.py @@ -407,16 +407,18 @@ class FirefoxProfile(Profile): # Also ensure that those are not getting disabled. # see: https://developer.mozilla.org/en/Installing_extensions 'extensions.enabledScopes': 5, 'extensions.autoDisableScopes': 10, # Don't send the list of installed addons to AMO 'extensions.getAddons.cache.enabled': False, # Don't install distribution add-ons from the app folder 'extensions.installDistroAddons': False, + # Dont' run the add-on compatibility check during start-up + 'extensions.showMismatchUI': False, # Don't automatically update add-ons 'extensions.update.enabled': False, # Don't open a dialog to show available add-on updates 'extensions.update.notifyUser': False, # Enable test mode to run multiple tests in parallel 'focusmanager.testmode': True, # Enable test mode to not raise an OS level dialog for location sharing 'geo.provider.testing': True,
new file mode 100644 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/update.properties @@ -0,0 +1,17 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# LOCALIZATION NOTE (addonUpdateTitle) +# %S will be replace with the localized name of the application +addonUpdateTitle=%S Update + +# LOCALIZATION NOTE (addonUpdateMessage) +# %S will be replace with the localized name of the application +addonUpdateMessage=%S is updating your extensions… + +addonUpdateCancelMessage=Still updating. Want to wait? + +# LOCALIZATION NOTE (addonUpdateCancelButton) +# %S will be replace with the localized name of the application +addonUpdateCancelButton=Stop update and launch %S
--- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -88,16 +88,17 @@ locale/@AB_CD@/mozapps/downloads/unknownContentType.properties (%chrome/mozapps/downloads/unknownContentType.properties) locale/@AB_CD@/mozapps/downloads/unknownContentType.dtd (%chrome/mozapps/downloads/unknownContentType.dtd) locale/@AB_CD@/mozapps/downloads/settingsChange.dtd (%chrome/mozapps/downloads/settingsChange.dtd) locale/@AB_CD@/mozapps/downloads/downloads.properties (%chrome/mozapps/downloads/downloads.properties) locale/@AB_CD@/mozapps/extensions/extensions.dtd (%chrome/mozapps/extensions/extensions.dtd) #ifndef MOZ_FENNEC locale/@AB_CD@/mozapps/extensions/extensions.properties (%chrome/mozapps/extensions/extensions.properties) locale/@AB_CD@/mozapps/extensions/blocklist.dtd (%chrome/mozapps/extensions/blocklist.dtd) + locale/@AB_CD@/mozapps/extensions/update.properties (%chrome/mozapps/extensions/update.properties) #endif locale/@AB_CD@/mozapps/handling/handling.dtd (%chrome/mozapps/handling/handling.dtd) locale/@AB_CD@/mozapps/handling/handling.properties (%chrome/mozapps/handling/handling.properties) locale/@AB_CD@/mozapps/preferences/changemp.dtd (%chrome/mozapps/preferences/changemp.dtd) locale/@AB_CD@/mozapps/preferences/removemp.dtd (%chrome/mozapps/preferences/removemp.dtd) locale/@AB_CD@/mozapps/preferences/preferences.properties (%chrome/mozapps/preferences/preferences.properties) locale/@AB_CD@/mozapps/profile/createProfileWizard.dtd (%chrome/mozapps/profile/createProfileWizard.dtd) locale/@AB_CD@/mozapps/profile/profileSelection.properties (%chrome/mozapps/profile/profileSelection.properties)
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/content/update.css @@ -0,0 +1,26 @@ +body { + font: message-box; + min-width: 480px; +} + +#message { + font-size: 14px; +} + +#message, #cancel-section { + margin: 10px 5px; +} + +#progress { + width: calc(100% - 10px); + margin: 0 5px; +} + +#cancel-section { + display: flex; + justify-content: space-between; +} + +#cancel-message { + vertical-align: middle; +}
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/content/update.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <script src="update.js"></script> + <link rel="stylesheet" href="chrome://mozapps/content/extensions/update.css"> + </head> + <body> + <div> + <div id="message"></div> + + <progress id="progress" val="0" max="1"></progress> + + <div id="cancel-section"> + <span id="cancel-message"></span> + <button id="cancel-btn"></button> + </div> + </div> + </body> +</html>
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/content/update.js @@ -0,0 +1,24 @@ +"use strict"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +let BRAND_PROPS = "chrome://branding/locale/brand.properties"; +let UPDATE_PROPS = "chrome://mozapps/locale/extensions/update.properties"; + +let appName = Services.strings.createBundle(BRAND_PROPS) + .GetStringFromName("brandShortName"); +let bundle = Services.strings.createBundle(UPDATE_PROPS); + +let titleText = bundle.formatStringFromName("addonUpdateTitle", [appName], 1); +let messageText = bundle.formatStringFromName("addonUpdateMessage", [appName], 1); +let cancelText = bundle.GetStringFromName("addonUpdateCancelMessage"); +let cancelButtonText = bundle.formatStringFromName("addonUpdateCancelButton", [appName], 1); + +document.title = titleText; + +window.addEventListener("load", e => { + document.getElementById("message").textContent = messageText; + document.getElementById("cancel-message").textContent = cancelText; + document.getElementById("cancel-btn").textContent = cancelButtonText; + window.sizeToContent(); +});
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm +++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm @@ -330,16 +330,19 @@ var AddonTestUtils = { Services.prefs.setIntPref("extensions.autoDisableScopes", 0); // And scan for changes at startup Services.prefs.setIntPref("extensions.startupScanScopes", 15); // By default, don't cache add-ons in AddonRepository.jsm Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", false); + // Disable the compatibility updates window by default + Services.prefs.setBoolPref("extensions.showMismatchUI", false); + // Point update checks to the local machine for fast failures Services.prefs.setCharPref("extensions.update.url", "http://127.0.0.1/updateURL"); Services.prefs.setCharPref("extensions.update.background.url", "http://127.0.0.1/updateBackgroundURL"); Services.prefs.setCharPref("extensions.blocklist.url", "http://127.0.0.1/blocklistURL"); Services.prefs.setCharPref("services.settings.server", "http://localhost/dummy-kinto/v1"); // By default ignore bundled add-ons Services.prefs.setBoolPref("extensions.installDistroAddons", false);
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -59,16 +59,17 @@ const nsIFile = Components.Constructor(" const PREF_DB_SCHEMA = "extensions.databaseSchema"; const PREF_XPI_STATE = "extensions.xpiState"; const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL"; const PREF_BOOTSTRAP_ADDONS = "extensions.bootstrappedAddons"; const PREF_PENDING_OPERATIONS = "extensions.pendingOperations"; const PREF_EM_EXTENSION_FORMAT = "extensions."; const PREF_EM_ENABLED_SCOPES = "extensions.enabledScopes"; const PREF_EM_STARTUP_SCAN_SCOPES = "extensions.startupScanScopes"; +const PREF_EM_SHOW_MISMATCH_UI = "extensions.showMismatchUI"; const PREF_XPI_ENABLED = "xpinstall.enabled"; const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required"; const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest"; const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest"; // xpinstall.signatures.required only supported in dev builds const PREF_XPI_SIGNATURES_REQUIRED = "xpinstall.signatures.required"; const PREF_XPI_SIGNATURES_DEV_ROOT = "xpinstall.signatures.dev-root"; const PREF_LANGPACK_SIGNATURES = "extensions.langpacks.signatures.required"; @@ -1742,16 +1743,19 @@ var XPIProvider = { // The value of the minCompatibleAppVersion preference minCompatibleAppVersion: null, // The value of the minCompatiblePlatformVersion preference minCompatiblePlatformVersion: null, // A Map of active addons to their bootstrapScope by ID activeAddons: new Map(), // True if the platform could have activated extensions extensionsActive: false, + // True if all of the add-ons found during startup were installed in the + // application install location + allAppGlobal: true, // New distribution addons awaiting permissions approval newDistroAddons: null, // Keep track of startup phases for telemetry runPhase: XPI_STARTING, // Per-addon telemetry information _telemetryDetails: {}, // Have we started shutting down bootstrap add-ons? _closing: false, @@ -2029,16 +2033,26 @@ var XPIProvider = { Services.obs.addObserver(this, NOTIFICATION_TOOLBOX_CONNECTION_CHANGE); let flushCaches = this.checkForChanges(aAppChanged, aOldAppVersion, aOldPlatformVersion); AddonManagerPrivate.markProviderSafe(this); + if (aAppChanged && !this.allAppGlobal && + Services.prefs.getBoolPref(PREF_EM_SHOW_MISMATCH_UI, true) && + AddonManager.updateEnabled) { + let addonsToUpdate = this.shouldForceUpdateCheck(aAppChanged); + if (addonsToUpdate) { + this.noLegacyStartupCheck(addonsToUpdate); + flushCaches = true; + } + } + if (flushCaches) { Services.obs.notifyObservers(null, "startupcache-invalidate"); // UI displayed early in startup (like the compatibility UI) may have // caused us to cache parts of the skin or locale in memory. These must // be flushed to allow extension provided skins and locales to take full // effect Services.obs.notifyObservers(null, "chrome-flush-skin-caches"); Services.obs.notifyObservers(null, "chrome-flush-caches"); @@ -2259,16 +2273,165 @@ var XPIProvider = { let data = {oldVersion: addon.version}; let method = callUpdate ? "update" : "install"; this.callBootstrapMethod(newAddon, file, method, reason, data); } } } }, + /** + * If the application has been upgraded and there are add-ons outside the + * application directory then we may need to synchronize compatibility + * information but only if the mismatch UI isn't disabled. + * + * @returns null if no update check is needed, otherwise an array of add-on + * IDs to check for updates. + */ + shouldForceUpdateCheck(aAppChanged) { + AddonManagerPrivate.recordSimpleMeasure("XPIDB_metadata_age", AddonRepository.metadataAge()); + + let startupChanges = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED); + logger.debug("shouldForceUpdateCheck startupChanges: " + startupChanges.toSource()); + AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_disabled", startupChanges.length); + + let forceUpdate = []; + if (startupChanges.length > 0) { + let addons = XPIDatabase.getAddons(); + for (let addon of addons) { + if ((startupChanges.includes(addon.id)) && + (addon.permissions() & AddonManager.PERM_CAN_UPGRADE) && + (!addon.isCompatible || isDisabledLegacy(addon))) { + logger.debug("shouldForceUpdateCheck: can upgrade disabled add-on " + addon.id); + forceUpdate.push(addon.id); + } + } + } + + if (forceUpdate.length > 0) { + return forceUpdate; + } + + return null; + }, + + /** + * Perform startup check for updates of legacy extensions. + * This runs during startup when an app update has made some add-ons + * incompatible and legacy add-on support is diasabled. + * In this case, we just do a quiet update check. + * + * @param {Array<string>} ids The ids of the addons to check for updates. + * + * @returns {Set<string>} The ids of any addons that were updated. These + * addons will have been started by the update + * process so they should not be started by the + * regular bootstrap startup code. + */ + noLegacyStartupCheck(ids) { + let started = new Set(); + const DIALOG = "chrome://mozapps/content/extensions/update.html"; + const SHOW_DIALOG_DELAY = 1000; + const SHOW_CANCEL_DELAY = 30000; + + // Keep track of a value between 0 and 1 indicating the progress + // for each addon. Just combine these linearly into a single + // value for the progress bar in the update dialog. + let updateProgress = val => {}; + let progressByID = new Map(); + function setProgress(id, val) { + progressByID.set(id, val); + updateProgress(Array.from(progressByID.values()).reduce((a, b) => a + b) / progressByID.size); + } + + // Do an update check for one addon and try to apply the update if + // there is one. Progress for the check is arbitrarily defined as + // 10% done when the update check is done, between 10-90% during the + // download, then 100% when the update has been installed. + let checkOne = async (id) => { + logger.debug(`Checking for updates to disabled addon ${id}\n`); + + setProgress(id, 0); + + let addon = await AddonManager.getAddonByID(id); + let install = await new Promise(resolve => addon.findUpdates({ + onUpdateFinished() { resolve(null); }, + onUpdateAvailable(addon, install) { resolve(install); }, + }, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED)); + + if (!install) { + setProgress(id, 1); + return; + } + + setProgress(id, 0.1); + + let installPromise = new Promise(resolve => { + let finish = () => { + setProgress(id, 1); + resolve(); + }; + install.addListener({ + onDownloadProgress() { + if (install.maxProgress != 0) { + setProgress(id, 0.1 + 0.8 * install.progress / install.maxProgress); + } + }, + onDownloadEnded() { + setProgress(id, 0.9); + }, + onDownloadFailed: finish, + onInstallFailed: finish, + onInstallEnded() { + started.add(id); + AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED, id); + finish(); + }, + }); + }); + install.install(); + await installPromise; + }; + + let finished = false; + Promise.all(ids.map(checkOne)).then(() => { finished = true; }); + + let window; + let timer = setTimeout(() => { + const FEATURES = "chrome,dialog,centerscreen,scrollbars=no"; + window = Services.ww.openWindow(null, DIALOG, "", FEATURES, null); + + let cancelDiv; + window.addEventListener("DOMContentLoaded", e => { + let progress = window.document.getElementById("progress"); + updateProgress = val => { progress.value = val; }; + + cancelDiv = window.document.getElementById("cancel-section"); + cancelDiv.setAttribute("style", "display: none;"); + + let cancelBtn = window.document.getElementById("cancel-btn"); + cancelBtn.addEventListener("click", e => { finished = true; }); + }); + + timer = setTimeout(() => { + cancelDiv.removeAttribute("style"); + window.sizeToContent(); + }, SHOW_CANCEL_DELAY - SHOW_DIALOG_DELAY); + }, SHOW_DIALOG_DELAY); + + Services.tm.spinEventLoopUntil(() => finished); + + clearTimeout(timer); + if (window) { + window.close(); + } + + return started; + }, + async updateSystemAddons() { let systemAddonLocation = XPIProvider.installLocationsByName[KEY_APP_SYSTEM_ADDONS]; if (!systemAddonLocation) return; // Don't do anything in safe mode if (Services.appinfo.inSafeMode) return;
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -1440,16 +1440,20 @@ this.XPIDatabaseReconcile = { let previousVisible = this.getVisibleAddons(previousAddons); let currentVisible = this.flattenByID(currentAddons, hideLocation); // Pass over the new set of visible add-ons, record any changes that occurred // during startup and call bootstrap install/uninstall scripts as necessary for (let [id, currentAddon] of currentVisible) { let previousAddon = previousVisible.get(id); + // Note if any visible add-on is not in the application install location + if (currentAddon._installLocation.name != KEY_APP_GLOBAL) + XPIProvider.allAppGlobal = false; + let isActive = !currentAddon.disabled && !currentAddon.pendingUninstall; let wasActive = previousAddon ? previousAddon.active : currentAddon.active; if (!previousAddon) { // If we had a manifest for this add-on it was a staged install and // so wasn't something recovered from a corrupt database let wasStaged = !!loadedManifest(currentAddon._installLocation, id);
--- a/toolkit/mozapps/extensions/jar.mn +++ b/toolkit/mozapps/extensions/jar.mn @@ -9,16 +9,19 @@ toolkit.jar: content/mozapps/extensions/extensions.css (content/extensions.css) content/mozapps/extensions/extensions.js (content/extensions.js) * content/mozapps/extensions/extensions.xml (content/extensions.xml) content/mozapps/extensions/updateinfo.xsl (content/updateinfo.xsl) content/mozapps/extensions/blocklist.xul (content/blocklist.xul) content/mozapps/extensions/blocklist.js (content/blocklist.js) content/mozapps/extensions/blocklist.css (content/blocklist.css) content/mozapps/extensions/blocklist.xml (content/blocklist.xml) + content/mozapps/extensions/update.html (content/update.html) + content/mozapps/extensions/update.js (content/update.js) + content/mozapps/extensions/update.css (content/update.css) content/mozapps/extensions/eula.xul (content/eula.xul) content/mozapps/extensions/eula.js (content/eula.js) content/mozapps/extensions/pluginPrefs.xul (content/pluginPrefs.xul) content/mozapps/extensions/pluginPrefs.js (content/pluginPrefs.js) content/mozapps/extensions/OpenH264-license.txt (content/OpenH264-license.txt) #endif content/mozapps/xpinstall/xpinstallConfirm.xul (content/xpinstallConfirm.xul) content/mozapps/xpinstall/xpinstallConfirm.js (content/xpinstallConfirm.js)