mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-05 13:45:46 +00:00
Bug 794937 - Make updates work from the Metro front end, add handling for 1 instance handling updates. r=rstrong
This commit is contained in:
parent
f906b641d5
commit
2b27a1ede9
@ -120,6 +120,7 @@ pref("app.update.cert.maxErrors", 5);
|
||||
// |app.update.url.override| user preference has been set for testing updates or
|
||||
// when the |app.update.cert.checkAttributes| preference is set to false. Also,
|
||||
// the |app.update.url.override| preference should ONLY be used for testing.
|
||||
// IMPORTANT! metro.js should also be updated for updates to certs.X.issuerName
|
||||
pref("app.update.certs.1.issuerName", "OU=Equifax Secure Certificate Authority,O=Equifax,C=US");
|
||||
pref("app.update.certs.1.commonName", "aus3.mozilla.org");
|
||||
|
||||
|
@ -121,6 +121,11 @@ function appUpdater()
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aus.isOtherInstanceHandlingUpdates) {
|
||||
this.selectPanel("otherInstanceHandlingUpdates");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDownloading) {
|
||||
this.startDownload();
|
||||
return;
|
||||
|
@ -76,6 +76,9 @@
|
||||
<hbox id="noUpdatesFound" align="center">
|
||||
<label>&update.noUpdatesFound;</label>
|
||||
</hbox>
|
||||
<hbox id="otherInstanceHandlingUpdates" align="center">
|
||||
<label>&update.otherInstanceHandlingUpdates;</label>
|
||||
</hbox>
|
||||
<hbox id="manualUpdate" align="center">
|
||||
<label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
|
||||
</hbox>
|
||||
|
@ -47,6 +47,8 @@
|
||||
<!ENTITY update.noUpdatesFound "&brandShortName; is up to date">
|
||||
<!-- LOCALIZATION NOTE (update.adminDisabled): try to make the localized text short (see bug 596813 for screenshots). -->
|
||||
<!ENTITY update.adminDisabled "Updates disabled by your system administrator">
|
||||
<!-- LOCALIZATION NOTE (update.otherInstanceHandlingUpdates): try to make the localized text short -->
|
||||
<!ENTITY update.otherInstanceHandlingUpdates "&brandShortName; is being updated by another instance">
|
||||
|
||||
<!-- LOCALIZATION NOTE (update.failed.start,update.failed.linkText,update.failed.end):
|
||||
update.failed.start, update.failed.linkText, and update.failed.end all go into
|
||||
|
@ -154,12 +154,6 @@ var BrowserUI = {
|
||||
Util.dumpLn("Exception in delay load module:", ex.message);
|
||||
}
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
// Check for updates in progress
|
||||
let updatePrompt = Cc["@mozilla.org/updates/update-prompt;1"].createInstance(Ci.nsIUpdatePrompt);
|
||||
updatePrompt.checkForUpdates();
|
||||
#endif
|
||||
|
||||
// check for left over crash reports and submit them if found.
|
||||
if (BrowserUI.startupCrashCheck()) {
|
||||
Browser.selectedTab = BrowserUI.newOrSelectTab("about:crash");
|
||||
|
@ -12,8 +12,6 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
const NS_APP_CACHE_PARENT_DIR = "cachePDir";
|
||||
const XRE_UPDATE_ROOT_DIR = "UpdRootD";
|
||||
const ENVVAR_UPDATE_DIR = "UPDATES_DIRECTORY";
|
||||
|
||||
function DirectoryProvider() {}
|
||||
|
||||
@ -33,20 +31,8 @@ DirectoryProvider.prototype = {
|
||||
default:
|
||||
return profile;
|
||||
}
|
||||
} else if (prop == XRE_UPDATE_ROOT_DIR) {
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
if (env.exists(ENVVAR_UPDATE_DIR)) {
|
||||
let path = env.get(ENVVAR_UPDATE_DIR);
|
||||
if (path) {
|
||||
let localFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
localFile.initWithPath(path);
|
||||
return localFile;
|
||||
}
|
||||
}
|
||||
let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
||||
return dm.defaultDownloadsDirectory;
|
||||
}
|
||||
|
||||
|
||||
// We are retuning null to show failure instead for throwing an error. The
|
||||
// interface is called quite a bit and throwing an error is noisy. Returning
|
||||
// null works with the way the interface is called [see bug 529077]
|
||||
|
@ -36,8 +36,4 @@ ifdef MOZ_SAFE_BROWSING
|
||||
EXTRA_COMPONENTS += SafeBrowsing.js
|
||||
endif
|
||||
|
||||
ifdef MOZ_UPDATER
|
||||
EXTRA_COMPONENTS += UpdatePrompt.js
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -1,243 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const UPDATE_NOTIFICATION_NAME = "update-app";
|
||||
const UPDATE_NOTIFICATION_ICON = "drawable://alert_download_progress";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gUpdateBundle", function aus_gUpdateBundle() {
|
||||
return Services.strings.createBundle("chrome://mozapps/locale/update/updates.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function aus_gBrandBundle() {
|
||||
return Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function aus_gBrowserBundle() {
|
||||
return Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "LocaleRepository", function() {
|
||||
Cu.import("resource://gre/modules/LocaleRepository.jsm");
|
||||
return LocaleRepository;
|
||||
});
|
||||
|
||||
function getPref(func, preference, defaultValue) {
|
||||
try {
|
||||
return Services.prefs[func](preference);
|
||||
} catch (e) {}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Update Prompt
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function UpdatePrompt() { }
|
||||
|
||||
UpdatePrompt.prototype = {
|
||||
classID: Components.ID("{88b3eb21-d072-4e3b-886d-f89d8c49fe59}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdatePrompt, Ci.nsIRequestObserver, Ci.nsIProgressEventSink]),
|
||||
|
||||
get _enabled() {
|
||||
return !getPref("getBoolPref", "app.update.silent", false);
|
||||
},
|
||||
|
||||
_showNotification: function UP__showNotif(aUpdate, aTitle, aText, aImageUrl, aMode) {
|
||||
let observer = {
|
||||
updatePrompt: this,
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "alertclickcallback":
|
||||
this.updatePrompt._handleUpdate(aUpdate, aMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
notifier.showAlertNotification(aImageUrl, aTitle, aText, true, "", observer, UPDATE_NOTIFICATION_NAME);
|
||||
},
|
||||
|
||||
_handleUpdate: function UP__handleUpdate(aUpdate, aMode) {
|
||||
if (aMode == "available") {
|
||||
let window = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let title = gUpdateBundle.GetStringFromName("updatesfound_" + aUpdate.type + ".title");
|
||||
let brandName = gBrandBundle.GetStringFromName("brandShortName");
|
||||
|
||||
// Unconditionally use the "major" type here as for now it is always a new version
|
||||
// without additional description required for a minor update message
|
||||
let message = gUpdateBundle.formatStringFromName("intro_major", [brandName, aUpdate.displayVersion], 2);
|
||||
let button0 = gUpdateBundle.GetStringFromName("okButton");
|
||||
let button1 = gUpdateBundle.GetStringFromName("askLaterButton");
|
||||
let prompt = Services.prompt;
|
||||
let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_IS_STRING + prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_IS_STRING;
|
||||
|
||||
let download = (prompt.confirmEx(window, title, message, flags, button0, button1, null, null, {value: false}) == 0);
|
||||
if (download) {
|
||||
// Start downloading the update in the background
|
||||
let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService);
|
||||
if (aus.downloadUpdate(aUpdate, true) != "failed") {
|
||||
let title = gBrowserBundle.formatStringFromName("alertDownloadsStart", [aUpdate.name], 1);
|
||||
this._showNotification(aUpdate, title, "", UPDATE_NOTIFICATION_ICON, "download");
|
||||
|
||||
// Add this UI as a listener for active downloads
|
||||
aus.addDownloadListener(this);
|
||||
}
|
||||
}
|
||||
} else if(aMode == "downloaded") {
|
||||
// Notify all windows that an application quit has been requested
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
|
||||
// If nothing aborted, restart the app
|
||||
if (cancelQuit.data == false) {
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateDownloadProgress: function UP__updateDownloadProgress(aProgress, aTotal) {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
|
||||
if (progressListener)
|
||||
progressListener.onProgress(UPDATE_NOTIFICATION_NAME, aProgress, aTotal);
|
||||
},
|
||||
|
||||
// -------------------------
|
||||
// nsIUpdatePrompt interface
|
||||
// -------------------------
|
||||
|
||||
// Right now this is used only to check for updates in progress
|
||||
checkForUpdates: function UP_checkForUpdates() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService);
|
||||
if (!aus.isDownloading)
|
||||
return;
|
||||
|
||||
let updateManager = Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager);
|
||||
|
||||
let updateName = updateManager.activeUpdate ? updateManager.activeUpdate.name : gBrandBundle.GetStringFromName("brandShortName");
|
||||
let title = gBrowserBundle.formatStringFromName("alertDownloadsStart", [updateName], 1);
|
||||
|
||||
this._showNotification(updateManager.activeUpdate, title, "", UPDATE_NOTIFICATION_ICON, "downloading");
|
||||
|
||||
aus.removeDownloadListener(this); // just in case it's already added
|
||||
aus.addDownloadListener(this);
|
||||
},
|
||||
|
||||
showUpdateAvailable: function UP_showUpdateAvailable(aUpdate) {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
const PREF_APP_UPDATE_SKIPNOTIFICATION = "app.update.skipNotification";
|
||||
|
||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SKIPNOTIFICATION) &&
|
||||
Services.prefs.getBoolPref(PREF_APP_UPDATE_SKIPNOTIFICATION)) {
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_SKIPNOTIFICATION, false);
|
||||
|
||||
// Notification was already displayed and clicked, so jump to the next step:
|
||||
// ask the user about downloading update
|
||||
this._handleUpdate(aUpdate, "available");
|
||||
return;
|
||||
}
|
||||
|
||||
let stringsPrefix = "updateAvailable_" + aUpdate.type + ".";
|
||||
let title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [aUpdate.name], 1);
|
||||
let text = gUpdateBundle.GetStringFromName(stringsPrefix + "text");
|
||||
let imageUrl = "";
|
||||
this._showNotification(aUpdate, title, text, imageUrl, "available");
|
||||
},
|
||||
|
||||
showUpdateDownloaded: function UP_showUpdateDownloaded(aUpdate, aBackground) {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
},
|
||||
|
||||
_showDownloadedNotification: function UP_showDlNotification(aUpdate) {
|
||||
let stringsPrefix = "updateDownloaded_" + aUpdate.type + ".";
|
||||
let title = gUpdateBundle.formatStringFromName(stringsPrefix + "title", [aUpdate.name], 1);
|
||||
let text = gUpdateBundle.GetStringFromName(stringsPrefix + "text");
|
||||
let imageUrl = "";
|
||||
this._showNotification(aUpdate, title, text, imageUrl, "downloaded");
|
||||
},
|
||||
|
||||
_uninstalling: [],
|
||||
_installing: [],
|
||||
_currentUpdate: null,
|
||||
|
||||
showUpdateInstalled: function UP_showUpdateInstalled() {
|
||||
if (!this._enabled || !getPref("getBoolPref", "app.update.showInstalledUI", false))
|
||||
return;
|
||||
|
||||
let title = gBrandBundle.GetStringFromName("brandShortName");
|
||||
let text = gUpdateBundle.GetStringFromName("installSuccess");
|
||||
let imageUrl = "";
|
||||
this._showNotification(aUpdate, title, text, imageUrl, "installed");
|
||||
},
|
||||
|
||||
showUpdateError: function UP_showUpdateError(aUpdate) {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
if (aUpdate.state == "failed") {
|
||||
var title = gBrandBundle.GetStringFromName("brandShortName");
|
||||
let text = gUpdateBundle.GetStringFromName("updaterIOErrorTitle");
|
||||
let imageUrl = "";
|
||||
this._showNotification(aUpdate, title, text, imageUrl, "error");
|
||||
}
|
||||
},
|
||||
|
||||
showUpdateHistory: function UP_showUpdateHistory(aParent) {
|
||||
// NOT IMPL
|
||||
},
|
||||
|
||||
// ----------------------------
|
||||
// nsIRequestObserver interface
|
||||
// ----------------------------
|
||||
|
||||
// When the data transfer begins
|
||||
onStartRequest: function(request, context) {
|
||||
// NOT IMPL
|
||||
},
|
||||
|
||||
// When the data transfer ends
|
||||
onStopRequest: function(request, context, status) {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
|
||||
if (progressListener)
|
||||
progressListener.onCancel(UPDATE_NOTIFICATION_NAME);
|
||||
|
||||
|
||||
let aus = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService);
|
||||
aus.removeDownloadListener(this);
|
||||
},
|
||||
|
||||
// ------------------------------
|
||||
// nsIProgressEventSink interface
|
||||
// ------------------------------
|
||||
|
||||
// When new data has been downloaded
|
||||
onProgress: function(request, context, progress, maxProgress) {
|
||||
this._updateDownloadProgress(progress, maxProgress);
|
||||
},
|
||||
|
||||
// When we have new status text
|
||||
onStatus: function(request, context, status, statusText) {
|
||||
// NOT IMPL
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdatePrompt]);
|
@ -84,8 +84,3 @@ contract @mozilla.org/safebrowsing/application;1 {aadaed90-6c03-42d0-924a-fc6119
|
||||
category app-startup SafeBrowsing service,@mozilla.org/safebrowsing/application;1
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
# UpdatePrompt.js
|
||||
component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js
|
||||
contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49fe59}
|
||||
#endif
|
||||
|
@ -395,21 +395,111 @@ pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616
|
||||
// Override some named colors to avoid inverse OS themes
|
||||
|
||||
/* app update prefs */
|
||||
pref("app.update.timer", 60000); // milliseconds (1 min)
|
||||
|
||||
#ifdef MOZ_UPDATER
|
||||
// temp
|
||||
pref("app.update.enabled", false);
|
||||
pref("app.update.timerFirstInterval", 20000); // milliseconds
|
||||
pref("app.update.auto", false);
|
||||
pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
|
||||
pref("app.update.mode", 1);
|
||||
pref("app.update.silent", false);
|
||||
pref("app.update.url", "https://aus2.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%-xul/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml");
|
||||
|
||||
// Whether or not app updates are enabled
|
||||
pref("app.update.enabled", true);
|
||||
|
||||
// This preference turns on app.update.mode and allows automatic download and
|
||||
// install to take place. We use a separate boolean toggle for this to make
|
||||
// the UI easier to construct.
|
||||
pref("app.update.auto", true);
|
||||
|
||||
// Defines how the Application Update Service notifies the user about updates:
|
||||
//
|
||||
// AUM Set to: Minor Releases: Major Releases:
|
||||
// 0 download no prompt download no prompt
|
||||
// 1 download no prompt download no prompt if no incompatibilities
|
||||
// 2 download no prompt prompt
|
||||
//
|
||||
// See chart in nsUpdateService.js source for more details
|
||||
pref("app.update.mode", 0);
|
||||
|
||||
// If set to true, the Update Service will present no UI for any event.
|
||||
pref("app.update.silent", true);
|
||||
|
||||
// If set to true, the Update Service will apply updates in the background
|
||||
// when it finishes downloading them.
|
||||
pref("app.update.staging.enabled", true);
|
||||
|
||||
// Update service URL:
|
||||
pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
|
||||
// Show the Update Checking/Ready UI when the user was idle for x seconds
|
||||
pref("app.update.idletime", 60);
|
||||
|
||||
// Whether or not we show a dialog box informing the user that the update was
|
||||
// successfully applied. This is off in Firefox by default since we show a
|
||||
// upgrade start page instead! Other apps may wish to show this UI, and supply
|
||||
// a whatsNewURL field in their brand.properties that contains a link to a page
|
||||
// which tells users what's new in this new update.
|
||||
pref("app.update.showInstalledUI", false);
|
||||
|
||||
// 0 = suppress prompting for incompatibilities if there are updates available
|
||||
// to newer versions of installed addons that resolve them.
|
||||
// 1 = suppress prompting for incompatibilities only if there are VersionInfo
|
||||
// updates available to installed addons that resolve them, not newer
|
||||
// versions.
|
||||
pref("app.update.incompatible.mode", 0);
|
||||
|
||||
// Whether or not to attempt using the service for updates.
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
pref("app.update.service.enabled", true);
|
||||
#endif
|
||||
|
||||
// The minimum delay in seconds for the timer to fire.
|
||||
// default=2 minutes
|
||||
pref("app.update.timerMinimumDelay", 120);
|
||||
|
||||
// Enables some extra Application Update Logging (can reduce performance)
|
||||
pref("app.update.log", false);
|
||||
|
||||
// The number of general background check failures to allow before notifying the
|
||||
// user of the failure. User initiated update checks always notify the user of
|
||||
// the failure.
|
||||
pref("app.update.backgroundMaxErrors", 10);
|
||||
|
||||
// When |app.update.cert.requireBuiltIn| is true or not specified the
|
||||
// final certificate and all certificates the connection is redirected to before
|
||||
// the final certificate for the url specified in the |app.update.url|
|
||||
// preference must be built-in.
|
||||
pref("app.update.cert.requireBuiltIn", true);
|
||||
|
||||
// When |app.update.cert.checkAttributes| is true or not specified the
|
||||
// certificate attributes specified in the |app.update.certs.| preference branch
|
||||
// are checked against the certificate for the url specified by the
|
||||
// |app.update.url| preference.
|
||||
pref("app.update.cert.checkAttributes", true);
|
||||
|
||||
// The number of certificate attribute check failures to allow for background
|
||||
// update checks before notifying the user of the failure. User initiated update
|
||||
// checks always notify the user of the certificate attribute check failure.
|
||||
pref("app.update.cert.maxErrors", 5);
|
||||
|
||||
// The |app.update.certs.| preference branch contains branches that are
|
||||
// sequentially numbered starting at 1 that contain attribute name / value
|
||||
// pairs for the certificate used by the server that hosts the update xml file
|
||||
// as specified in the |app.update.url| preference. When these preferences are
|
||||
// present the following conditions apply for a successful update check:
|
||||
// 1. the uri scheme must be https
|
||||
// 2. the preference name must exist as an attribute name on the certificate and
|
||||
// the value for the name must be the same as the value for the attribute name
|
||||
// on the certificate.
|
||||
// If these conditions aren't met it will be treated the same as when there is
|
||||
// no update available. This validation will not be performed when the
|
||||
// |app.update.url.override| user preference has been set for testing updates or
|
||||
// when the |app.update.cert.checkAttributes| preference is set to false. Also,
|
||||
// the |app.update.url.override| preference should ONLY be used for testing.
|
||||
// IMPORTANT! firefox.js should also be updated for updates to certs.X.issuerName
|
||||
pref("app.update.certs.1.issuerName", "OU=Equifax Secure Certificate Authority,O=Equifax,C=US");
|
||||
pref("app.update.certs.1.commonName", "aus3.mozilla.org");
|
||||
pref("app.update.certs.2.issuerName", "CN=Thawte SSL CA,O=\"Thawte, Inc.\",C=US");
|
||||
pref("app.update.certs.2.commonName", "aus3.mozilla.org");
|
||||
|
||||
// User-settable override to app.update.url for testing purposes.
|
||||
//pref("app.update.url.override", "");
|
||||
|
||||
// replace newlines with spaces on paste into single-line text boxes
|
||||
pref("editor.singleLine.pasteNewlines", 2);
|
||||
|
||||
|
@ -19,7 +19,7 @@ interface nsIFile;
|
||||
* be downloaded and applied to a version of this application so that it
|
||||
* can be updated.
|
||||
*/
|
||||
[scriptable, uuid(1134957d-9449-481b-a515-4d88b9998278)]
|
||||
[scriptable, uuid(dc8fb8a9-3a53-4031-9469-2a5197ea30e7)]
|
||||
interface nsIUpdatePatch : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -429,6 +429,15 @@ interface nsIApplicationUpdateService : nsISupports
|
||||
*/
|
||||
readonly attribute boolean canApplyUpdates;
|
||||
|
||||
/**
|
||||
* Whether or not a different instance is handling updates of this
|
||||
* installation. This currently only ever returns true on Windows
|
||||
* when 2 instances of an application are open or when both the Metro
|
||||
* and Desktop browsers are open. Only one of the instances will actually
|
||||
* handle updates for the installation.
|
||||
*/
|
||||
readonly attribute boolean isOtherInstanceHandlingUpdates;
|
||||
|
||||
/**
|
||||
* Whether the Update Service is able to stage updates.
|
||||
*/
|
||||
|
@ -385,6 +385,108 @@ function testWriteAccess(updateTestFile, createDirectory) {
|
||||
updateTestFile.remove(false);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
/**
|
||||
* Closes a Win32 handle
|
||||
*
|
||||
* @param handle The handle to close
|
||||
*/
|
||||
function closeHandle(handle) {
|
||||
var lib = ctypes.open("kernel32.dll");
|
||||
var CloseHandle = lib.declare("CloseHandle",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.int32_t, /* success */
|
||||
ctypes.void_t.ptr); /* handle */
|
||||
CloseHandle(handle);
|
||||
lib.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mutex.
|
||||
*
|
||||
* @param aAllowExisting false if the function should fail if the mutex exists
|
||||
* @return The Win32 handle to the mutex
|
||||
*/
|
||||
function createMutex(name, aAllowExisting) {
|
||||
if (aAllowExisting === undefined) {
|
||||
aAllowExisting = true;
|
||||
}
|
||||
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
const INITIAL_OWN = 1;
|
||||
const ERROR_ALREADY_EXISTS = 0xB7;
|
||||
var lib = ctypes.open("kernel32.dll");
|
||||
var CreateMutexW = lib.declare("CreateMutexW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.void_t.ptr, /* return handle */
|
||||
ctypes.void_t.ptr, /* security attributes */
|
||||
ctypes.int32_t, /* initial owner */
|
||||
ctypes.jschar.ptr); /* name */
|
||||
|
||||
var handle = CreateMutexW(null, INITIAL_OWN, name);
|
||||
var alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
|
||||
if (handle && !handle.isNull() && !aAllowExisting && alreadyExists) {
|
||||
closeHandle(handle);
|
||||
handle = null;
|
||||
}
|
||||
lib.close();
|
||||
|
||||
if (handle && handle.isNull())
|
||||
handle = null;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a unique mutex name for the installation
|
||||
*
|
||||
* @param aGlobal true if the function should return a global mutex. A global
|
||||
* mutex is valid across different sessions
|
||||
* @return Global mutex path
|
||||
*/
|
||||
function getPerInstallationMutexName(aGlobal) {
|
||||
if (aGlobal === undefined) {
|
||||
aGobal = true;
|
||||
}
|
||||
let hasher = Components.classes["@mozilla.org/security/hash;1"].
|
||||
createInstance(Components.interfaces.nsICryptoHash);
|
||||
hasher.init(hasher.SHA1);
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
var exeFile = Services.dirsvc.get("XREExeF", Components.interfaces.nsILocalFile);
|
||||
|
||||
let converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
var data = converter.convertToByteArray(exeFile.path.toLowerCase());
|
||||
|
||||
hasher.update(data, data.length);
|
||||
return (aGlobal ? "Global\\" : "") + "MozillaUpdateMutex-" + hasher.finish(true);
|
||||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
/**
|
||||
* Whether or not the current instance has the update mutex. The update mutex
|
||||
* gives protection against 2 browsers from the same installation updating:
|
||||
* 1) Running multiple profiles from the same installation path
|
||||
* 2) Running a Metro and Desktop browser at the same time from the same path
|
||||
* 3) 2 browsers running in 2 different user sessions from the same path
|
||||
*
|
||||
* @return true if this instance holds the update mutex
|
||||
*/
|
||||
function hasUpdateMutex() {
|
||||
#ifdef XP_WIN
|
||||
if (!this._updateMutexHandle) {
|
||||
this._updateMutexHandle = createMutex(getPerInstallationMutexName(true), false);
|
||||
}
|
||||
|
||||
return !!this._updateMutexHandle;
|
||||
#else
|
||||
return true;
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpdates() {
|
||||
function submitHasPermissionsTelemetryPing(val) {
|
||||
try {
|
||||
@ -480,6 +582,12 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasUpdateMutex()) {
|
||||
LOG("gCanApplyUpdates - unable to apply updates because another " +
|
||||
"browser is already handling updates for this installation.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("gCanApplyUpdates - able to apply updates");
|
||||
submitHasPermissionsTelemetryPing(true);
|
||||
return true;
|
||||
@ -524,6 +632,12 @@ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdates", function aus_gCanStageUpda
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasUpdateMutex()) {
|
||||
LOG("gCanStageUpdates - unable to stage updates because another " +
|
||||
"browser is already handling updates for this installation.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("gCanStageUpdates - able to stage updates");
|
||||
return true;
|
||||
});
|
||||
@ -552,6 +666,12 @@ XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckF
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasUpdateMutex()) {
|
||||
LOG("gCanCheckForUpdates - unable to apply updates because another " +
|
||||
"browser is already handling updates for this installation.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("gCanCheckForUpdates - able to check for updates");
|
||||
return true;
|
||||
});
|
||||
@ -2524,6 +2644,14 @@ UpdateService.prototype = {
|
||||
return gCanStageUpdates;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
get isOtherInstanceHandlingUpdates() {
|
||||
return !hasUpdateMutex();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user