mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 782881 - Protect against attempts to use the Add-ons Manager APIs after shutdown. r=Unfocused
Bug 782881 - Protect against attempts to use the Add-ons Manager APIs after shutdown. r=Unfocused
This commit is contained in:
parent
7ca24186f5
commit
a47d2f37ce
@ -7,6 +7,9 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const PREFS_GUID = CommonUtils.encodeBase64URL(Services.appinfo.ID);
|
||||
|
||||
loadAddonTestFunctions();
|
||||
startupManager();
|
||||
|
||||
function makePersona(id) {
|
||||
return {
|
||||
id: id || Math.random().toString(),
|
||||
|
@ -367,6 +367,7 @@ function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags)
|
||||
}
|
||||
|
||||
var gStarted = false;
|
||||
var gStartupComplete = false;
|
||||
var gCheckCompatibility = true;
|
||||
var gStrictCompatibility = true;
|
||||
var gCheckUpdateSecurityDefault = true;
|
||||
@ -443,6 +444,8 @@ var AddonManagerInternal = {
|
||||
if (gStarted)
|
||||
return;
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
|
||||
let appChanged = undefined;
|
||||
|
||||
let oldAppVersion = null;
|
||||
@ -535,6 +538,9 @@ var AddonManagerInternal = {
|
||||
}
|
||||
}
|
||||
|
||||
// Once we start calling providers we must allow all normal methods to work.
|
||||
gStarted = true;
|
||||
|
||||
this.callProviders("startup", appChanged, oldAppVersion,
|
||||
oldPlatformVersion);
|
||||
|
||||
@ -544,7 +550,7 @@ var AddonManagerInternal = {
|
||||
delete this.startupChanges[type];
|
||||
}
|
||||
|
||||
gStarted = true;
|
||||
gStartupComplete = true;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -667,6 +673,8 @@ var AddonManagerInternal = {
|
||||
* up everything in order for automated tests to fake restarts.
|
||||
*/
|
||||
shutdown: function AMI_shutdown() {
|
||||
LOG("shutdown");
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this);
|
||||
Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this);
|
||||
Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this);
|
||||
@ -674,7 +682,10 @@ var AddonManagerInternal = {
|
||||
Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this);
|
||||
Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this);
|
||||
|
||||
this.callProviders("shutdown");
|
||||
// Always clean up listeners, but only shutdown providers if they've been
|
||||
// started.
|
||||
if (gStarted)
|
||||
this.callProviders("shutdown");
|
||||
|
||||
this.managerListeners.splice(0, this.managerListeners.length);
|
||||
this.installListeners.splice(0, this.installListeners.length);
|
||||
@ -683,6 +694,7 @@ var AddonManagerInternal = {
|
||||
for (let type in this.startupChanges)
|
||||
delete this.startupChanges[type];
|
||||
gStarted = false;
|
||||
gStartupComplete = false;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -691,6 +703,11 @@ var AddonManagerInternal = {
|
||||
* @see nsIObserver
|
||||
*/
|
||||
observe: function AMI_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "xpcom-shutdown") {
|
||||
this.shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aData) {
|
||||
case PREF_EM_CHECK_COMPATIBILITY: {
|
||||
let oldValue = gCheckCompatibility;
|
||||
@ -852,6 +869,10 @@ var AddonManagerInternal = {
|
||||
* that can be updated.
|
||||
*/
|
||||
backgroundUpdateCheck: function AMI_backgroundUpdateCheck() {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
let hotfixID = this.hotfixID;
|
||||
|
||||
let checkHotfix = hotfixID &&
|
||||
@ -1033,7 +1054,7 @@ var AddonManagerInternal = {
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (gStarted)
|
||||
if (gStartupComplete)
|
||||
return;
|
||||
|
||||
// Ensure that an ID is only listed in one type of change
|
||||
@ -1062,7 +1083,7 @@ var AddonManagerInternal = {
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
if (gStarted)
|
||||
if (gStartupComplete)
|
||||
return;
|
||||
|
||||
if (!(aType in this.startupChanges))
|
||||
@ -1079,6 +1100,10 @@ var AddonManagerInternal = {
|
||||
* The method on the listeners to call
|
||||
*/
|
||||
callManagerListeners: function AMI_callManagerListeners(aMethod, ...aArgs) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1106,6 +1131,10 @@ var AddonManagerInternal = {
|
||||
* @return false if any of the listeners returned false, true otherwise
|
||||
*/
|
||||
callInstallListeners: function AMI_callInstallListeners(aMethod, aExtraListeners, ...aArgs) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1143,6 +1172,10 @@ var AddonManagerInternal = {
|
||||
* The method on the listeners to call
|
||||
*/
|
||||
callAddonListeners: function AMI_callAddonListeners(aMethod, ...aArgs) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1173,6 +1206,10 @@ var AddonManagerInternal = {
|
||||
* time the application is restarted
|
||||
*/
|
||||
notifyAddonChanged: function AMI_notifyAddonChanged(aID, aType, aPendingRestart) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (aID && typeof aID != "string")
|
||||
throw Components.Exception("aID must be a string or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1190,6 +1227,10 @@ var AddonManagerInternal = {
|
||||
* update.
|
||||
*/
|
||||
updateAddonAppDisabledStates: function AMI_updateAddonAppDisabledStates() {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
this.callProviders("updateAddonAppDisabledStates");
|
||||
},
|
||||
|
||||
@ -1201,6 +1242,10 @@ var AddonManagerInternal = {
|
||||
* Function to call when operation is complete.
|
||||
*/
|
||||
updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1242,6 +1287,10 @@ var AddonManagerInternal = {
|
||||
getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype,
|
||||
aHash, aName, aIconURL,
|
||||
aVersion, aLoadGroup) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aUrl || typeof aUrl != "string")
|
||||
throw Components.Exception("aURL must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1300,6 +1349,10 @@ var AddonManagerInternal = {
|
||||
* @throws if the aFile or aCallback arguments are not specified
|
||||
*/
|
||||
getInstallForFile: function AMI_getInstallForFile(aFile, aCallback, aMimetype) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!(aFile instanceof Ci.nsIFile))
|
||||
throw Components.Exception("aFile must be a nsIFile",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1340,6 +1393,10 @@ var AddonManagerInternal = {
|
||||
* @throws If the aCallback argument is not specified
|
||||
*/
|
||||
getInstallsByTypes: function AMI_getInstallsByTypes(aTypes, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1372,6 +1429,10 @@ var AddonManagerInternal = {
|
||||
* A callback which will be passed an array of AddonInstalls
|
||||
*/
|
||||
getAllInstalls: function AMI_getAllInstalls(aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
this.getInstallsByTypes(null, aCallback);
|
||||
},
|
||||
|
||||
@ -1383,6 +1444,10 @@ var AddonManagerInternal = {
|
||||
* @return true if installation is enabled for the mimetype
|
||||
*/
|
||||
isInstallEnabled: function AMI_isInstallEnabled(aMimetype) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1407,6 +1472,10 @@ var AddonManagerInternal = {
|
||||
* @return true if the source is allowed to install this mimetype
|
||||
*/
|
||||
isInstallAllowed: function AMI_isInstallAllowed(aMimetype, aURI) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1441,6 +1510,10 @@ var AddonManagerInternal = {
|
||||
aSource,
|
||||
aURI,
|
||||
aInstalls) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aMimetype || typeof aMimetype != "string")
|
||||
throw Components.Exception("aMimetype must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1544,6 +1617,10 @@ var AddonManagerInternal = {
|
||||
* @throws if the aID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonByID: function AMI_getAddonByID(aID, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aID || typeof aID != "string")
|
||||
throw Components.Exception("aID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1578,6 +1655,10 @@ var AddonManagerInternal = {
|
||||
* @throws if the aGUID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonBySyncGUID: function AMI_getAddonBySyncGUID(aGUID, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!aGUID || typeof aGUID != "string")
|
||||
throw Components.Exception("aGUID must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1613,6 +1694,10 @@ var AddonManagerInternal = {
|
||||
* @throws if the aID or aCallback arguments are not specified
|
||||
*/
|
||||
getAddonsByIDs: function AMI_getAddonsByIDs(aIDs, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!Array.isArray(aIDs))
|
||||
throw Components.Exception("aIDs must be an array",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1647,6 +1732,10 @@ var AddonManagerInternal = {
|
||||
* @throws if the aCallback argument is not specified
|
||||
*/
|
||||
getAddonsByTypes: function AMI_getAddonsByTypes(aTypes, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1679,6 +1768,14 @@ var AddonManagerInternal = {
|
||||
* A callback which will be passed an array of Addons
|
||||
*/
|
||||
getAllAddons: function AMI_getAllAddons(aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (typeof aCallback != "function")
|
||||
throw Components.Exception("aCallback must be a function",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
this.getAddonsByTypes(null, aCallback);
|
||||
},
|
||||
|
||||
@ -1694,6 +1791,10 @@ var AddonManagerInternal = {
|
||||
*/
|
||||
getAddonsWithOperationsByTypes:
|
||||
function AMI_getAddonsWithOperationsByTypes(aTypes, aCallback) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (aTypes && !Array.isArray(aTypes))
|
||||
throw Components.Exception("aTypes must be an array or null",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -1780,7 +1881,6 @@ var AddonManagerInternal = {
|
||||
throw Components.Exception("aListener must be an AddonListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
||||
let pos = 0;
|
||||
while (pos < this.addonListeners.length) {
|
||||
if (this.addonListeners[pos] == aListener)
|
||||
@ -1920,10 +2020,6 @@ var AddonManagerPrivate = {
|
||||
AddonManagerInternal.unregisterProvider(aProvider);
|
||||
},
|
||||
|
||||
shutdown: function AMP_shutdown() {
|
||||
AddonManagerInternal.shutdown();
|
||||
},
|
||||
|
||||
backgroundUpdateCheck: function AMP_backgroundUpdateCheck() {
|
||||
AddonManagerInternal.backgroundUpdateCheck();
|
||||
},
|
||||
|
@ -49,19 +49,8 @@ function amManager() {
|
||||
|
||||
amManager.prototype = {
|
||||
observe: function AMC_observe(aSubject, aTopic, aData) {
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
switch (aTopic) {
|
||||
case "addons-startup":
|
||||
os.addObserver(this, "xpcom-shutdown", false);
|
||||
if (aTopic == "addons-startup")
|
||||
AddonManagerPrivate.startup();
|
||||
break;
|
||||
case "xpcom-shutdown":
|
||||
os.removeObserver(this, "xpcom-shutdown");
|
||||
AddonManagerPrivate.shutdown();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -393,7 +393,8 @@ function shutdownManager() {
|
||||
}, "addon-repository-shutdown", false);
|
||||
|
||||
obs.notifyObservers(null, "quit-application-granted", null);
|
||||
gInternalManager.observe(null, "xpcom-shutdown", null);
|
||||
let scope = Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
scope.AddonManagerInternal.shutdown();
|
||||
gInternalManager = null;
|
||||
|
||||
AddonRepository.shutdown();
|
||||
@ -416,7 +417,7 @@ function shutdownManager() {
|
||||
|
||||
// Force the XPIProvider provider to reload to better
|
||||
// simulate real-world usage.
|
||||
let scope = Components.utils.import("resource://gre/modules/XPIProvider.jsm");
|
||||
scope = Components.utils.import("resource://gre/modules/XPIProvider.jsm");
|
||||
AddonManagerPrivate.unregisterProvider(scope.XPIProvider);
|
||||
Components.utils.unload("resource://gre/modules/XPIProvider.jsm");
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ function run_test() {
|
||||
gTestserver.registerDirectory("/data/", do_get_file("data"));
|
||||
gTestserver.start(4444);
|
||||
|
||||
startupManager();
|
||||
|
||||
// initialize the blocklist with no entries
|
||||
var blocklistFile = gProfD.clone();
|
||||
|
@ -13,6 +13,7 @@ function test_string_compare() {
|
||||
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
startupManager();
|
||||
|
||||
do_test_pending();
|
||||
|
||||
|
60
toolkit/mozapps/extensions/test/xpcshell/test_shutdown.js
Normal file
60
toolkit/mozapps/extensions/test/xpcshell/test_shutdown.js
Normal file
@ -0,0 +1,60 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Verify that API functions fail if the Add-ons Manager isn't initialised.
|
||||
|
||||
const IGNORE = ["escapeAddonURI", "shouldAutoUpdate", "getStartupChanges",
|
||||
"addTypeListener", "removeTypeListener",
|
||||
"addAddonListener", "removeAddonListener",
|
||||
"addInstallListener", "removeInstallListener",
|
||||
"addManagerListener", "removeManagerListener"];
|
||||
|
||||
const IGNORE_PRIVATE = ["AddonAuthor", "AddonCompatibilityOverride",
|
||||
"AddonScreenshot", "AddonType", "startup", "shutdown",
|
||||
"registerProvider", "unregisterProvider",
|
||||
"addStartupChange", "removeStartupChange"];
|
||||
|
||||
function test_functions() {
|
||||
for (let prop in AddonManager) {
|
||||
if (typeof AddonManager[prop] != "function")
|
||||
continue;
|
||||
if (IGNORE.indexOf(prop) != -1)
|
||||
continue;
|
||||
|
||||
try {
|
||||
do_print("AddonManager." + prop);
|
||||
AddonManager[prop]();
|
||||
do_throw(prop + " did not throw an exception");
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
|
||||
do_throw(prop + " threw an unexpected exception: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
for (let prop in AddonManagerPrivate) {
|
||||
if (typeof AddonManagerPrivate[prop] != "function")
|
||||
continue;
|
||||
if (IGNORE_PRIVATE.indexOf(prop) != -1)
|
||||
continue;
|
||||
|
||||
try {
|
||||
do_print("AddonManagerPrivate." + prop);
|
||||
AddonManagerPrivate[prop]();
|
||||
do_throw(prop + " did not throw an exception");
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
|
||||
do_throw(prop + " threw an unexpected exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
test_functions();
|
||||
startupManager();
|
||||
shutdownManager();
|
||||
test_functions();
|
||||
}
|
@ -193,6 +193,7 @@ fail-if = os == "android"
|
||||
[test_pref_properties.js]
|
||||
[test_registry.js]
|
||||
[test_safemode.js]
|
||||
[test_shutdown.js]
|
||||
[test_startup.js]
|
||||
# Bug 676992: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
|
Loading…
Reference in New Issue
Block a user