mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 794211: Check for updates after coming online when a check fails because the network is offline. r=bbondy r=rstrong
This commit is contained in:
parent
8429f9c41d
commit
64fcf6b336
@ -468,10 +468,6 @@ pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
|
||||
|
||||
// Interval at which update manifest is fetched. In units of seconds.
|
||||
pref("app.update.interval", 86400); // 1 day
|
||||
// First interval to elapse before checking for update. In units of
|
||||
// milliseconds. Capped at 10 seconds.
|
||||
pref("app.update.timerFirstInterval", 3600000); // 1 hour
|
||||
pref("app.update.timerMinimumDelay", 3600); // 1 hour in seconds
|
||||
// Don't throttle background updates.
|
||||
pref("app.update.download.backgroundInterval", 0);
|
||||
|
||||
|
@ -151,6 +151,7 @@ const WRITE_ERROR_SHARING_VIOLATION_NOPID = 48;
|
||||
const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100;
|
||||
const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
|
||||
const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
|
||||
const NETWORK_ERROR_OFFLINE = 111;
|
||||
|
||||
const DOWNLOAD_CHUNK_SIZE = 300000; // bytes
|
||||
const DOWNLOAD_BACKGROUND_INTERVAL = 600; // seconds
|
||||
@ -1496,6 +1497,11 @@ UpdateService.prototype = {
|
||||
*/
|
||||
_incompatAddonsCount: 0,
|
||||
|
||||
/**
|
||||
* Whether or not the service registered the "online" observer.
|
||||
*/
|
||||
_registeredOnlineObserver: false,
|
||||
|
||||
/**
|
||||
* Handle Observer Service notifications
|
||||
* @param subject
|
||||
@ -1511,6 +1517,9 @@ UpdateService.prototype = {
|
||||
// Clean up any extant updates
|
||||
this._postUpdateProcessing();
|
||||
break;
|
||||
case "network:offline-status-changed":
|
||||
this._offlineStatusChanged(data);
|
||||
break;
|
||||
case "xpcom-shutdown":
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
|
||||
@ -1789,6 +1798,83 @@ UpdateService.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Register an observer when the network comes online, so we can short-circuit
|
||||
* the app.update.interval when there isn't connectivity
|
||||
*/
|
||||
_registerOnlineObserver: function AUS__registerOnlineObserver() {
|
||||
if (this._registeredOnlineObserver) {
|
||||
LOG("UpdateService:_registerOnlineObserver - observer already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("UpdateService:_registerOnlineObserver - waiting for the network to " +
|
||||
"be online, then forcing another check");
|
||||
|
||||
Services.obs.addObserver(this, "network:offline-status-changed", false);
|
||||
this._registeredOnlineObserver = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called from the network:offline-status-changed observer.
|
||||
*/
|
||||
_offlineStatusChanged: function AUS__offlineStatusChanged(status) {
|
||||
if (status !== "online") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "network:offline-status-changed");
|
||||
this._registeredOnlineObserver = false;
|
||||
|
||||
LOG("UpdateService:_offlineStatusChanged - network is online, forcing " +
|
||||
"another background check");
|
||||
|
||||
// the background checker is contained in notify
|
||||
this.notify(null);
|
||||
},
|
||||
|
||||
// nsIUpdateCheckListener
|
||||
onProgress: function AUS_onProgress(request, position, totalSize) {
|
||||
},
|
||||
|
||||
onCheckComplete: function AUS_onCheckComplete(request, updates, updateCount) {
|
||||
this._selectAndInstallUpdate(updates);
|
||||
},
|
||||
|
||||
onError: function AUS_onError(request, update) {
|
||||
LOG("UpdateService:onError - error during background update: " +
|
||||
update.statusText);
|
||||
|
||||
var maxErrors;
|
||||
var errCount;
|
||||
if (update.errorCode == NETWORK_ERROR_OFFLINE) {
|
||||
// Register an online observer to try again
|
||||
this._registerOnlineObserver();
|
||||
return;
|
||||
}
|
||||
else if (update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
|
||||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE) {
|
||||
errCount = getPref("getIntPref", PREF_APP_UPDATE_CERT_ERRORS, 0);
|
||||
errCount++;
|
||||
Services.prefs.setIntPref(PREF_APP_UPDATE_CERT_ERRORS, errCount);
|
||||
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_CERT_MAXERRORS, 5);
|
||||
}
|
||||
else {
|
||||
update.errorCode = BACKGROUNDCHECK_MULTIPLE_FAILURES;
|
||||
errCount = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDERRORS, 0);
|
||||
errCount++;
|
||||
Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, errCount);
|
||||
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDMAXERRORS,
|
||||
10);
|
||||
}
|
||||
|
||||
if (errCount >= maxErrors) {
|
||||
var prompter = Cc["@mozilla.org/updates/update-prompt;1"].
|
||||
createInstance(Ci.nsIUpdatePrompt);
|
||||
prompter.showUpdateError(update);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Notified when a timer fires
|
||||
* @param timer
|
||||
@ -1799,55 +1885,7 @@ UpdateService.prototype = {
|
||||
if (this.isDownloading || this._downloader && this._downloader.patchIsStaged)
|
||||
return;
|
||||
|
||||
var self = this;
|
||||
var listener = {
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onProgress: function AUS_notify_onProgress(request, position, totalSize) {
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onCheckComplete: function AUS_notify_onCheckComplete(request, updates,
|
||||
updateCount) {
|
||||
self._selectAndInstallUpdate(updates);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onError: function AUS_notify_onError(request, update) {
|
||||
LOG("UpdateService:notify:listener - error during background update: " +
|
||||
update.statusText);
|
||||
|
||||
var maxErrors;
|
||||
var errCount;
|
||||
if (update.errorCode == CERT_ATTR_CHECK_FAILED_NO_UPDATE ||
|
||||
update.errorCode == CERT_ATTR_CHECK_FAILED_HAS_UPDATE) {
|
||||
errCount = getPref("getIntPref", PREF_APP_UPDATE_CERT_ERRORS, 0);
|
||||
errCount++;
|
||||
Services.prefs.setIntPref(PREF_APP_UPDATE_CERT_ERRORS, errCount);
|
||||
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_CERT_MAXERRORS, 5);
|
||||
}
|
||||
else {
|
||||
update.errorCode = BACKGROUNDCHECK_MULTIPLE_FAILURES;
|
||||
errCount = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDERRORS, 0);
|
||||
errCount++;
|
||||
Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, errCount);
|
||||
maxErrors = getPref("getIntPref", PREF_APP_UPDATE_BACKGROUNDMAXERRORS,
|
||||
10);
|
||||
}
|
||||
|
||||
if (errCount >= maxErrors) {
|
||||
var prompter = Cc["@mozilla.org/updates/update-prompt;1"].
|
||||
createInstance(Ci.nsIUpdatePrompt);
|
||||
prompter.showUpdateError(update);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.backgroundChecker.checkForUpdates(listener, false);
|
||||
this.backgroundChecker.checkForUpdates(this, false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2307,6 +2345,7 @@ UpdateService.prototype = {
|
||||
|
||||
_xpcom_factory: UpdateServiceFactory,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIApplicationUpdateService,
|
||||
Ci.nsIUpdateCheckListener,
|
||||
Ci.nsIAddonUpdateCheckListener,
|
||||
Ci.nsITimerCallback,
|
||||
Ci.nsIObserver])
|
||||
@ -2843,6 +2882,11 @@ Checker.prototype = {
|
||||
// "looks" fine but there was probably an XML error or a bogus file.
|
||||
var update = new Update(null);
|
||||
update.statusText = getStatusTextFromCode(status, 200);
|
||||
if (status == Cr.NS_ERROR_OFFLINE) {
|
||||
// We use a separate constant here because nsIUpdate.errorCode is signed
|
||||
update.errorCode = NETWORK_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
this._callback.onError(request, update);
|
||||
|
||||
this._request = null;
|
||||
|
@ -91,7 +91,8 @@ XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() {
|
||||
return AUS_Cc["@mozilla.org/updates/update-service;1"].
|
||||
getService(AUS_Ci.nsIApplicationUpdateService).
|
||||
QueryInterface(AUS_Ci.nsITimerCallback).
|
||||
QueryInterface(AUS_Ci.nsIObserver);
|
||||
QueryInterface(AUS_Ci.nsIObserver).
|
||||
QueryInterface(AUS_Ci.nsIUpdateCheckListener);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager",
|
||||
|
@ -114,6 +114,9 @@ var gTestserver;
|
||||
var gXHR;
|
||||
var gXHRCallback;
|
||||
|
||||
var gUpdatePrompt;
|
||||
var gUpdatePromptCallback;
|
||||
|
||||
var gCheckFunc;
|
||||
var gResponseBody;
|
||||
var gResponseStatusCode = 200;
|
||||
@ -1502,6 +1505,7 @@ function overrideXHR(callback) {
|
||||
gXHR.contractID, gXHR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
|
||||
* and onload nsIDomEventListener handleEvent.
|
||||
@ -1566,6 +1570,63 @@ xhr.prototype = {
|
||||
get wrappedJSObject() { return this; }
|
||||
};
|
||||
|
||||
function overrideUpdatePrompt(callback) {
|
||||
var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
|
||||
gUpdatePrompt = new UpdatePrompt();
|
||||
gUpdatePromptCallback = callback;
|
||||
registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription,
|
||||
gUpdatePrompt.contractID, gUpdatePrompt);
|
||||
}
|
||||
|
||||
function UpdatePrompt() {
|
||||
var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded",
|
||||
"showUpdateError", "showUpdateHistory", "showUpdateInstalled"];
|
||||
|
||||
fns.forEach(function(promptFn) {
|
||||
UpdatePrompt.prototype[promptFn] = function() {
|
||||
if (!gUpdatePromptCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
var callback = gUpdatePromptCallback[promptFn];
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback.apply(gUpdatePromptCallback,
|
||||
Array.prototype.slice.call(arguments));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
UpdatePrompt.prototype = {
|
||||
flags: AUS_Ci.nsIClassInfo.SINGLETON,
|
||||
implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
getHelperForLanguage: function(language) null,
|
||||
getInterfaces: function(count) {
|
||||
var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt];
|
||||
count.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
classDescription: "UpdatePrompt",
|
||||
contractID: "@mozilla.org/updates/update-prompt;1",
|
||||
classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"),
|
||||
createInstance: function (outer, aIID) {
|
||||
if (outer == null)
|
||||
return gUpdatePrompt.QueryInterface(aIID);
|
||||
throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(AUS_Ci.nsIClassInfo) ||
|
||||
aIID.equals(AUS_Ci.nsISupports) ||
|
||||
aIID.equals(AUS_Ci.nsIUpdatePrompt))
|
||||
return gUpdatePrompt;
|
||||
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Update check listener */
|
||||
const updateCheckListener = {
|
||||
onProgress: function UCL_onProgress(request, position, totalSize) {
|
||||
@ -1586,12 +1647,13 @@ const updateCheckListener = {
|
||||
onError: function UCL_onError(request, update) {
|
||||
gRequestURL = request.channel.originalURI.spec;
|
||||
gStatusCode = request.status;
|
||||
|
||||
gStatusText = update.statusText;
|
||||
logTestInfo("url = " + gRequestURL + ", " +
|
||||
"request.status = " + gStatusCode + ", " +
|
||||
"update.statusText = " + gStatusText);
|
||||
// Use a timeout to allow the XHR to complete
|
||||
do_execute_soon(gCheckFunc);
|
||||
do_execute_soon(gCheckFunc.bind(null, request, update));
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
|
86
toolkit/mozapps/update/test/unit/test_bug794211.js
Normal file
86
toolkit/mozapps/update/test/unit/test_bug794211.js
Normal file
@ -0,0 +1,86 @@
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
/* Offline retry test (Bug 794211) */
|
||||
|
||||
// Needs to be in sync w/ nsUpdateService.js
|
||||
const NETWORK_ERROR_OFFLINE = 111;
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
do_register_cleanup(end_test);
|
||||
DEBUG_AUS_TEST = true;
|
||||
|
||||
logTestInfo("test when an update check fails because the network is " +
|
||||
"offline that we check again when the network comes online. " +
|
||||
"(Bug 794211)");
|
||||
removeUpdateDirsAndFiles();
|
||||
setUpdateURLOverride();
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false);
|
||||
|
||||
overrideXHR(null);
|
||||
overrideUpdatePrompt(updatePrompt);
|
||||
standardInit();
|
||||
|
||||
do_execute_soon(run_test_pt1);
|
||||
}
|
||||
|
||||
function run_test_pt1() {
|
||||
gResponseBody = null;
|
||||
gCheckFunc = check_test_pt1;
|
||||
gXHRCallback = xhr_pt1;
|
||||
gUpdateChecker.checkForUpdates(updateCheckListener, true);
|
||||
}
|
||||
|
||||
function xhr_pt1() {
|
||||
gXHR.status = AUS_Cr.NS_ERROR_OFFLINE;
|
||||
gXHR.onerror({ target: gXHR });
|
||||
}
|
||||
|
||||
function check_test_pt1(request, update) {
|
||||
do_check_eq(gStatusCode, AUS_Cr.NS_ERROR_OFFLINE);
|
||||
do_check_eq(update.errorCode, NETWORK_ERROR_OFFLINE);
|
||||
|
||||
// Forward the error to AUS, which should register the online observer
|
||||
gAUS.onError(request, update);
|
||||
|
||||
// Trigger another check by notifying the offline status observer
|
||||
gXHRCallback = xhr_pt2;
|
||||
Services.obs.notifyObservers(gAUS, "network:offline-status-changed", "online");
|
||||
}
|
||||
|
||||
var updatePrompt = {
|
||||
showUpdateAvailable: function(update) {
|
||||
check_test_pt2(update);
|
||||
}
|
||||
};
|
||||
|
||||
function xhr_pt2() {
|
||||
var patches = getLocalPatchString();
|
||||
var updates = getLocalUpdateString(patches);
|
||||
var responseBody = getLocalUpdatesXMLString(updates);
|
||||
|
||||
gXHR.status = 200;
|
||||
gXHR.responseText = responseBody;
|
||||
try {
|
||||
var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(AUS_Ci.nsIDOMParser);
|
||||
gXHR.responseXML = parser.parseFromString(responseBody, "application/xml");
|
||||
}
|
||||
catch(e) { }
|
||||
gXHR.onload({ target: gXHR });
|
||||
}
|
||||
|
||||
function check_test_pt2(update) {
|
||||
// We just verify that there are updates to know the check succeeded.
|
||||
do_check_neq(update, null);
|
||||
do_check_eq(update.name, "App Update Test");
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function end_test() {
|
||||
cleanUp();
|
||||
}
|
@ -28,3 +28,4 @@ run-if = os == 'win'
|
||||
run-if = os == 'linux' || os == 'mac' || os == 'sunos'
|
||||
[test_bug497578.js]
|
||||
[test_bug595059.js]
|
||||
[test_bug794211.js]
|
||||
|
Loading…
Reference in New Issue
Block a user