1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/mozapps/extensions/AddonManager.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2814 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const Cc = Components.classes; 1.11 +const Ci = Components.interfaces; 1.12 +const Cr = Components.results; 1.13 +const Cu = Components.utils; 1.14 + 1.15 +// Cannot use Services.appinfo here, or else xpcshell-tests will blow up, as 1.16 +// most tests later register different nsIAppInfo implementations, which 1.17 +// wouldn't be reflected in Services.appinfo anymore, as the lazy getter 1.18 +// underlying it would have been initialized if we used it here. 1.19 +if ("@mozilla.org/xre/app-info;1" in Cc) { 1.20 + let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); 1.21 + if (runtime.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { 1.22 + // Refuse to run in child processes. 1.23 + throw new Error("You cannot use the AddonManager in child processes!"); 1.24 + } 1.25 +} 1.26 + 1.27 + 1.28 +const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion"; 1.29 +const PREF_DEFAULT_PROVIDERS_ENABLED = "extensions.defaultProviders.enabled"; 1.30 +const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; 1.31 +const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; 1.32 +const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion"; 1.33 +const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; 1.34 +const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility"; 1.35 +const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; 1.36 +const PREF_EM_UPDATE_BACKGROUND_URL = "extensions.update.background.url"; 1.37 +const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; 1.38 +const PREF_APP_UPDATE_AUTO = "app.update.auto"; 1.39 +const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; 1.40 +const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion"; 1.41 +const PREF_EM_HOTFIX_URL = "extensions.hotfix.url"; 1.42 +const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes"; 1.43 +const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs."; 1.44 +const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; 1.45 +const PREF_SELECTED_LOCALE = "general.useragent.locale"; 1.46 +const UNKNOWN_XPCOM_ABI = "unknownABI"; 1.47 + 1.48 +const UPDATE_REQUEST_VERSION = 2; 1.49 +const CATEGORY_UPDATE_PARAMS = "extension-update-params"; 1.50 + 1.51 +const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist"; 1.52 + 1.53 +const KEY_PROFILEDIR = "ProfD"; 1.54 +const KEY_APPDIR = "XCurProcD"; 1.55 +const FILE_BLOCKLIST = "blocklist.xml"; 1.56 + 1.57 +const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; 1.58 +const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility"; 1.59 +#ifdef MOZ_COMPATIBILITY_NIGHTLY 1.60 +var PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly"; 1.61 +#else 1.62 +var PREF_EM_CHECK_COMPATIBILITY; 1.63 +#endif 1.64 + 1.65 +const TOOLKIT_ID = "toolkit@mozilla.org"; 1.66 + 1.67 +const VALID_TYPES_REGEXP = /^[\w\-]+$/; 1.68 + 1.69 +Cu.import("resource://gre/modules/Services.jsm"); 1.70 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.71 +Cu.import("resource://gre/modules/AsyncShutdown.jsm"); 1.72 + 1.73 +XPCOMUtils.defineLazyModuleGetter(this, "Promise", 1.74 + "resource://gre/modules/Promise.jsm"); 1.75 +XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", 1.76 + "resource://gre/modules/addons/AddonRepository.jsm"); 1.77 +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", 1.78 + "resource://gre/modules/FileUtils.jsm"); 1.79 + 1.80 +XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() { 1.81 + let certUtils = {}; 1.82 + Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils); 1.83 + return certUtils; 1.84 +}); 1.85 + 1.86 + 1.87 +this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ]; 1.88 + 1.89 +const CATEGORY_PROVIDER_MODULE = "addon-provider-module"; 1.90 + 1.91 +// A list of providers to load by default 1.92 +const DEFAULT_PROVIDERS = [ 1.93 + "resource://gre/modules/addons/XPIProvider.jsm", 1.94 + "resource://gre/modules/LightweightThemeManager.jsm" 1.95 +]; 1.96 + 1.97 +Cu.import("resource://gre/modules/Log.jsm"); 1.98 +// Configure a logger at the parent 'addons' level to format 1.99 +// messages for all the modules under addons.* 1.100 +const PARENT_LOGGER_ID = "addons"; 1.101 +let parentLogger = Log.repository.getLogger(PARENT_LOGGER_ID); 1.102 +parentLogger.level = Log.Level.Warn; 1.103 +let formatter = new Log.BasicFormatter(); 1.104 +// Set parent logger (and its children) to append to 1.105 +// the Javascript section of the Browser Console 1.106 +parentLogger.addAppender(new Log.ConsoleAppender(formatter)); 1.107 +// Set parent logger (and its children) to 1.108 +// also append to standard out 1.109 +parentLogger.addAppender(new Log.DumpAppender(formatter)); 1.110 + 1.111 +// Create a new logger (child of 'addons' logger) 1.112 +// for use by the Addons Manager 1.113 +const LOGGER_ID = "addons.manager"; 1.114 +let logger = Log.repository.getLogger(LOGGER_ID); 1.115 + 1.116 +// Provide the ability to enable/disable logging 1.117 +// messages at runtime. 1.118 +// If the "extensions.logging.enabled" preference is 1.119 +// missing or 'false', messages at the WARNING and higher 1.120 +// severity should be logged to the JS console and standard error. 1.121 +// If "extensions.logging.enabled" is set to 'true', messages 1.122 +// at DEBUG and higher should go to JS console and standard error. 1.123 +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; 1.124 +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; 1.125 + 1.126 +/** 1.127 + * Preference listener which listens for a change in the 1.128 + * "extensions.logging.enabled" preference and changes the logging level of the 1.129 + * parent 'addons' level logger accordingly. 1.130 + */ 1.131 +var PrefObserver = { 1.132 + init: function PrefObserver_init() { 1.133 + Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); 1.134 + Services.obs.addObserver(this, "xpcom-shutdown", false); 1.135 + this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); 1.136 + }, 1.137 + 1.138 + observe: function PrefObserver_observe(aSubject, aTopic, aData) { 1.139 + if (aTopic == "xpcom-shutdown") { 1.140 + Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); 1.141 + Services.obs.removeObserver(this, "xpcom-shutdown"); 1.142 + } 1.143 + else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { 1.144 + let debugLogEnabled = false; 1.145 + try { 1.146 + debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); 1.147 + } 1.148 + catch (e) { 1.149 + } 1.150 + if (debugLogEnabled) { 1.151 + parentLogger.level = Log.Level.Debug; 1.152 + } 1.153 + else { 1.154 + parentLogger.level = Log.Level.Warn; 1.155 + } 1.156 + } 1.157 + } 1.158 +}; 1.159 + 1.160 +PrefObserver.init(); 1.161 + 1.162 +/** 1.163 + * Calls a callback method consuming any thrown exception. Any parameters after 1.164 + * the callback parameter will be passed to the callback. 1.165 + * 1.166 + * @param aCallback 1.167 + * The callback method to call 1.168 + */ 1.169 +function safeCall(aCallback, ...aArgs) { 1.170 + try { 1.171 + aCallback.apply(null, aArgs); 1.172 + } 1.173 + catch (e) { 1.174 + logger.warn("Exception calling callback", e); 1.175 + } 1.176 +} 1.177 + 1.178 +/** 1.179 + * Calls a method on a provider if it exists and consumes any thrown exception. 1.180 + * Any parameters after the dflt parameter are passed to the provider's method. 1.181 + * 1.182 + * @param aProvider 1.183 + * The provider to call 1.184 + * @param aMethod 1.185 + * The method name to call 1.186 + * @param aDefault 1.187 + * A default return value if the provider does not implement the named 1.188 + * method or throws an error. 1.189 + * @return the return value from the provider or dflt if the provider does not 1.190 + * implement method or throws an error 1.191 + */ 1.192 +function callProvider(aProvider, aMethod, aDefault, ...aArgs) { 1.193 + if (!(aMethod in aProvider)) 1.194 + return aDefault; 1.195 + 1.196 + try { 1.197 + return aProvider[aMethod].apply(aProvider, aArgs); 1.198 + } 1.199 + catch (e) { 1.200 + logger.error("Exception calling provider " + aMethod, e); 1.201 + return aDefault; 1.202 + } 1.203 +} 1.204 + 1.205 +/** 1.206 + * Gets the currently selected locale for display. 1.207 + * @return the selected locale or "en-US" if none is selected 1.208 + */ 1.209 +function getLocale() { 1.210 + try { 1.211 + if (Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE)) 1.212 + return Services.locale.getLocaleComponentForUserAgent(); 1.213 + } 1.214 + catch (e) { } 1.215 + 1.216 + try { 1.217 + let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE, 1.218 + Ci.nsIPrefLocalizedString); 1.219 + if (locale) 1.220 + return locale; 1.221 + } 1.222 + catch (e) { } 1.223 + 1.224 + try { 1.225 + return Services.prefs.getCharPref(PREF_SELECTED_LOCALE); 1.226 + } 1.227 + catch (e) { } 1.228 + 1.229 + return "en-US"; 1.230 +} 1.231 + 1.232 +/** 1.233 + * A helper class to repeatedly call a listener with each object in an array 1.234 + * optionally checking whether the object has a method in it. 1.235 + * 1.236 + * @param aObjects 1.237 + * The array of objects to iterate through 1.238 + * @param aMethod 1.239 + * An optional method name, if not null any objects without this method 1.240 + * will not be passed to the listener 1.241 + * @param aListener 1.242 + * A listener implementing nextObject and noMoreObjects methods. The 1.243 + * former will be called with the AsyncObjectCaller as the first 1.244 + * parameter and the object as the second. noMoreObjects will be passed 1.245 + * just the AsyncObjectCaller 1.246 + */ 1.247 +function AsyncObjectCaller(aObjects, aMethod, aListener) { 1.248 + this.objects = aObjects.slice(0); 1.249 + this.method = aMethod; 1.250 + this.listener = aListener; 1.251 + 1.252 + this.callNext(); 1.253 +} 1.254 + 1.255 +AsyncObjectCaller.prototype = { 1.256 + objects: null, 1.257 + method: null, 1.258 + listener: null, 1.259 + 1.260 + /** 1.261 + * Passes the next object to the listener or calls noMoreObjects if there 1.262 + * are none left. 1.263 + */ 1.264 + callNext: function AOC_callNext() { 1.265 + if (this.objects.length == 0) { 1.266 + this.listener.noMoreObjects(this); 1.267 + return; 1.268 + } 1.269 + 1.270 + let object = this.objects.shift(); 1.271 + if (!this.method || this.method in object) 1.272 + this.listener.nextObject(this, object); 1.273 + else 1.274 + this.callNext(); 1.275 + } 1.276 +}; 1.277 + 1.278 +/** 1.279 + * This represents an author of an add-on (e.g. creator or developer) 1.280 + * 1.281 + * @param aName 1.282 + * The name of the author 1.283 + * @param aURL 1.284 + * The URL of the author's profile page 1.285 + */ 1.286 +function AddonAuthor(aName, aURL) { 1.287 + this.name = aName; 1.288 + this.url = aURL; 1.289 +} 1.290 + 1.291 +AddonAuthor.prototype = { 1.292 + name: null, 1.293 + url: null, 1.294 + 1.295 + // Returns the author's name, defaulting to the empty string 1.296 + toString: function AddonAuthor_toString() { 1.297 + return this.name || ""; 1.298 + } 1.299 +} 1.300 + 1.301 +/** 1.302 + * This represents an screenshot for an add-on 1.303 + * 1.304 + * @param aURL 1.305 + * The URL to the full version of the screenshot 1.306 + * @param aWidth 1.307 + * The width in pixels of the screenshot 1.308 + * @param aHeight 1.309 + * The height in pixels of the screenshot 1.310 + * @param aThumbnailURL 1.311 + * The URL to the thumbnail version of the screenshot 1.312 + * @param aThumbnailWidth 1.313 + * The width in pixels of the thumbnail version of the screenshot 1.314 + * @param aThumbnailHeight 1.315 + * The height in pixels of the thumbnail version of the screenshot 1.316 + * @param aCaption 1.317 + * The caption of the screenshot 1.318 + */ 1.319 +function AddonScreenshot(aURL, aWidth, aHeight, aThumbnailURL, 1.320 + aThumbnailWidth, aThumbnailHeight, aCaption) { 1.321 + this.url = aURL; 1.322 + if (aWidth) this.width = aWidth; 1.323 + if (aHeight) this.height = aHeight; 1.324 + if (aThumbnailURL) this.thumbnailURL = aThumbnailURL; 1.325 + if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth; 1.326 + if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight; 1.327 + if (aCaption) this.caption = aCaption; 1.328 +} 1.329 + 1.330 +AddonScreenshot.prototype = { 1.331 + url: null, 1.332 + width: null, 1.333 + height: null, 1.334 + thumbnailURL: null, 1.335 + thumbnailWidth: null, 1.336 + thumbnailHeight: null, 1.337 + caption: null, 1.338 + 1.339 + // Returns the screenshot URL, defaulting to the empty string 1.340 + toString: function AddonScreenshot_toString() { 1.341 + return this.url || ""; 1.342 + } 1.343 +} 1.344 + 1.345 + 1.346 +/** 1.347 + * This represents a compatibility override for an addon. 1.348 + * 1.349 + * @param aType 1.350 + * Overrride type - "compatible" or "incompatible" 1.351 + * @param aMinVersion 1.352 + * Minimum version of the addon to match 1.353 + * @param aMaxVersion 1.354 + * Maximum version of the addon to match 1.355 + * @param aAppID 1.356 + * Application ID used to match appMinVersion and appMaxVersion 1.357 + * @param aAppMinVersion 1.358 + * Minimum version of the application to match 1.359 + * @param aAppMaxVersion 1.360 + * Maximum version of the application to match 1.361 + */ 1.362 +function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID, 1.363 + aAppMinVersion, aAppMaxVersion) { 1.364 + this.type = aType; 1.365 + this.minVersion = aMinVersion; 1.366 + this.maxVersion = aMaxVersion; 1.367 + this.appID = aAppID; 1.368 + this.appMinVersion = aAppMinVersion; 1.369 + this.appMaxVersion = aAppMaxVersion; 1.370 +} 1.371 + 1.372 +AddonCompatibilityOverride.prototype = { 1.373 + /** 1.374 + * Type of override - "incompatible" or "compatible". 1.375 + * Only "incompatible" is supported for now. 1.376 + */ 1.377 + type: null, 1.378 + 1.379 + /** 1.380 + * Min version of the addon to match. 1.381 + */ 1.382 + minVersion: null, 1.383 + 1.384 + /** 1.385 + * Max version of the addon to match. 1.386 + */ 1.387 + maxVersion: null, 1.388 + 1.389 + /** 1.390 + * Application ID to match. 1.391 + */ 1.392 + appID: null, 1.393 + 1.394 + /** 1.395 + * Min version of the application to match. 1.396 + */ 1.397 + appMinVersion: null, 1.398 + 1.399 + /** 1.400 + * Max version of the application to match. 1.401 + */ 1.402 + appMaxVersion: null 1.403 +}; 1.404 + 1.405 + 1.406 +/** 1.407 + * A type of add-on, used by the UI to determine how to display different types 1.408 + * of add-ons. 1.409 + * 1.410 + * @param aID 1.411 + * The add-on type ID 1.412 + * @param aLocaleURI 1.413 + * The URI of a localized properties file to get the displayable name 1.414 + * for the type from 1.415 + * @param aLocaleKey 1.416 + * The key for the string in the properties file or the actual display 1.417 + * name if aLocaleURI is null. Include %ID% to include the type ID in 1.418 + * the key 1.419 + * @param aViewType 1.420 + * The optional type of view to use in the UI 1.421 + * @param aUIPriority 1.422 + * The priority is used by the UI to list the types in order. Lower 1.423 + * values push the type higher in the list. 1.424 + * @param aFlags 1.425 + * An option set of flags that customize the display of the add-on in 1.426 + * the UI. 1.427 + */ 1.428 +function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) { 1.429 + if (!aID) 1.430 + throw Components.Exception("An AddonType must have an ID", Cr.NS_ERROR_INVALID_ARG); 1.431 + 1.432 + if (aViewType && aUIPriority === undefined) 1.433 + throw Components.Exception("An AddonType with a defined view must have a set UI priority", 1.434 + Cr.NS_ERROR_INVALID_ARG); 1.435 + 1.436 + if (!aLocaleKey) 1.437 + throw Components.Exception("An AddonType must have a displayable name", 1.438 + Cr.NS_ERROR_INVALID_ARG); 1.439 + 1.440 + this.id = aID; 1.441 + this.uiPriority = aUIPriority; 1.442 + this.viewType = aViewType; 1.443 + this.flags = aFlags; 1.444 + 1.445 + if (aLocaleURI) { 1.446 + this.__defineGetter__("name", function nameGetter() { 1.447 + delete this.name; 1.448 + let bundle = Services.strings.createBundle(aLocaleURI); 1.449 + this.name = bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID)); 1.450 + return this.name; 1.451 + }); 1.452 + } 1.453 + else { 1.454 + this.name = aLocaleKey; 1.455 + } 1.456 +} 1.457 + 1.458 +var gStarted = false; 1.459 +var gStartupComplete = false; 1.460 +var gCheckCompatibility = true; 1.461 +var gStrictCompatibility = true; 1.462 +var gCheckUpdateSecurityDefault = true; 1.463 +var gCheckUpdateSecurity = gCheckUpdateSecurityDefault; 1.464 +var gUpdateEnabled = true; 1.465 +var gAutoUpdateDefault = true; 1.466 +var gHotfixID = null; 1.467 + 1.468 +/** 1.469 + * This is the real manager, kept here rather than in AddonManager to keep its 1.470 + * contents hidden from API users. 1.471 + */ 1.472 +var AddonManagerInternal = { 1.473 + managerListeners: [], 1.474 + installListeners: [], 1.475 + addonListeners: [], 1.476 + typeListeners: [], 1.477 + providers: [], 1.478 + types: {}, 1.479 + startupChanges: {}, 1.480 + // Store telemetry details per addon provider 1.481 + telemetryDetails: {}, 1.482 + 1.483 + 1.484 + // A read-only wrapper around the types dictionary 1.485 + typesProxy: Proxy.create({ 1.486 + getOwnPropertyDescriptor: function typesProxy_getOwnPropertyDescriptor(aName) { 1.487 + if (!(aName in AddonManagerInternal.types)) 1.488 + return undefined; 1.489 + 1.490 + return { 1.491 + value: AddonManagerInternal.types[aName].type, 1.492 + writable: false, 1.493 + configurable: false, 1.494 + enumerable: true 1.495 + } 1.496 + }, 1.497 + 1.498 + getPropertyDescriptor: function typesProxy_getPropertyDescriptor(aName) { 1.499 + return this.getOwnPropertyDescriptor(aName); 1.500 + }, 1.501 + 1.502 + getOwnPropertyNames: function typesProxy_getOwnPropertyNames() { 1.503 + return Object.keys(AddonManagerInternal.types); 1.504 + }, 1.505 + 1.506 + getPropertyNames: function typesProxy_getPropertyNames() { 1.507 + return this.getOwnPropertyNames(); 1.508 + }, 1.509 + 1.510 + delete: function typesProxy_delete(aName) { 1.511 + // Not allowed to delete properties 1.512 + return false; 1.513 + }, 1.514 + 1.515 + defineProperty: function typesProxy_defineProperty(aName, aProperty) { 1.516 + // Ignore attempts to define properties 1.517 + }, 1.518 + 1.519 + fix: function typesProxy_fix(){ 1.520 + return undefined; 1.521 + }, 1.522 + 1.523 + // Despite MDC's claims to the contrary, it is required that this trap 1.524 + // be defined 1.525 + enumerate: function typesProxy_enumerate() { 1.526 + // All properties are enumerable 1.527 + return this.getPropertyNames(); 1.528 + } 1.529 + }), 1.530 + 1.531 + recordTimestamp: function AMI_recordTimestamp(name, value) { 1.532 + this.TelemetryTimestamps.add(name, value); 1.533 + }, 1.534 + 1.535 + validateBlocklist: function AMI_validateBlocklist() { 1.536 + let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]); 1.537 + 1.538 + // If there is no application shipped blocklist then there is nothing to do 1.539 + if (!appBlocklist.exists()) 1.540 + return; 1.541 + 1.542 + let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]); 1.543 + 1.544 + // If there is no blocklist in the profile then copy the application shipped 1.545 + // one there 1.546 + if (!profileBlocklist.exists()) { 1.547 + try { 1.548 + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); 1.549 + } 1.550 + catch (e) { 1.551 + logger.warn("Failed to copy the application shipped blocklist to the profile", e); 1.552 + } 1.553 + return; 1.554 + } 1.555 + 1.556 + let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. 1.557 + createInstance(Ci.nsIFileInputStream); 1.558 + try { 1.559 + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]. 1.560 + createInstance(Ci.nsIConverterInputStream); 1.561 + fileStream.init(appBlocklist, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); 1.562 + cstream.init(fileStream, "UTF-8", 0, 0); 1.563 + 1.564 + let data = ""; 1.565 + let str = {}; 1.566 + let read = 0; 1.567 + do { 1.568 + read = cstream.readString(0xffffffff, str); 1.569 + data += str.value; 1.570 + } while (read != 0); 1.571 + 1.572 + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. 1.573 + createInstance(Ci.nsIDOMParser); 1.574 + var doc = parser.parseFromString(data, "text/xml"); 1.575 + } 1.576 + catch (e) { 1.577 + logger.warn("Application shipped blocklist could not be loaded", e); 1.578 + return; 1.579 + } 1.580 + finally { 1.581 + try { 1.582 + fileStream.close(); 1.583 + } 1.584 + catch (e) { 1.585 + logger.warn("Unable to close blocklist file stream", e); 1.586 + } 1.587 + } 1.588 + 1.589 + // If the namespace is incorrect then ignore the application shipped 1.590 + // blocklist 1.591 + if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) { 1.592 + logger.warn("Application shipped blocklist has an unexpected namespace (" + 1.593 + doc.documentElement.namespaceURI + ")"); 1.594 + return; 1.595 + } 1.596 + 1.597 + // If there is no lastupdate information then ignore the application shipped 1.598 + // blocklist 1.599 + if (!doc.documentElement.hasAttribute("lastupdate")) 1.600 + return; 1.601 + 1.602 + // If the application shipped blocklist is older than the profile blocklist 1.603 + // then do nothing 1.604 + if (doc.documentElement.getAttribute("lastupdate") <= 1.605 + profileBlocklist.lastModifiedTime) 1.606 + return; 1.607 + 1.608 + // Otherwise copy the application shipped blocklist to the profile 1.609 + try { 1.610 + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); 1.611 + } 1.612 + catch (e) { 1.613 + logger.warn("Failed to copy the application shipped blocklist to the profile", e); 1.614 + } 1.615 + }, 1.616 + 1.617 + /** 1.618 + * Initializes the AddonManager, loading any known providers and initializing 1.619 + * them. 1.620 + */ 1.621 + startup: function AMI_startup() { 1.622 + try { 1.623 + if (gStarted) 1.624 + return; 1.625 + 1.626 + this.recordTimestamp("AMI_startup_begin"); 1.627 + 1.628 + // clear this for xpcshell test restarts 1.629 + for (let provider in this.telemetryDetails) 1.630 + delete this.telemetryDetails[provider]; 1.631 + 1.632 + let appChanged = undefined; 1.633 + 1.634 + let oldAppVersion = null; 1.635 + try { 1.636 + oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); 1.637 + appChanged = Services.appinfo.version != oldAppVersion; 1.638 + } 1.639 + catch (e) { } 1.640 + 1.641 + let oldPlatformVersion = null; 1.642 + try { 1.643 + oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION); 1.644 + } 1.645 + catch (e) { } 1.646 + 1.647 + if (appChanged !== false) { 1.648 + logger.debug("Application has been upgraded"); 1.649 + Services.prefs.setCharPref(PREF_EM_LAST_APP_VERSION, 1.650 + Services.appinfo.version); 1.651 + Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION, 1.652 + Services.appinfo.platformVersion); 1.653 + Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, 1.654 + (appChanged === undefined ? 0 : -1)); 1.655 + this.validateBlocklist(); 1.656 + } 1.657 + 1.658 +#ifndef MOZ_COMPATIBILITY_NIGHTLY 1.659 + PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." + 1.660 + Services.appinfo.version.replace(BRANCH_REGEXP, "$1"); 1.661 +#endif 1.662 + 1.663 + try { 1.664 + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); 1.665 + } catch (e) {} 1.666 + Services.prefs.addObserver(PREF_EM_CHECK_COMPATIBILITY, this, false); 1.667 + 1.668 + try { 1.669 + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); 1.670 + } catch (e) {} 1.671 + Services.prefs.addObserver(PREF_EM_STRICT_COMPATIBILITY, this, false); 1.672 + 1.673 + try { 1.674 + let defaultBranch = Services.prefs.getDefaultBranch(""); 1.675 + gCheckUpdateSecurityDefault = defaultBranch.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); 1.676 + } catch(e) {} 1.677 + 1.678 + try { 1.679 + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); 1.680 + } catch (e) {} 1.681 + Services.prefs.addObserver(PREF_EM_CHECK_UPDATE_SECURITY, this, false); 1.682 + 1.683 + try { 1.684 + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); 1.685 + } catch (e) {} 1.686 + Services.prefs.addObserver(PREF_EM_UPDATE_ENABLED, this, false); 1.687 + 1.688 + try { 1.689 + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); 1.690 + } catch (e) {} 1.691 + Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false); 1.692 + 1.693 + try { 1.694 + gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); 1.695 + } catch (e) {} 1.696 + Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false); 1.697 + 1.698 + let defaultProvidersEnabled = true; 1.699 + try { 1.700 + defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED); 1.701 + } catch (e) {} 1.702 + AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled); 1.703 + 1.704 + // Ensure all default providers have had a chance to register themselves 1.705 + if (defaultProvidersEnabled) { 1.706 + for (let url of DEFAULT_PROVIDERS) { 1.707 + try { 1.708 + let scope = {}; 1.709 + Components.utils.import(url, scope); 1.710 + // Sanity check - make sure the provider exports a symbol that 1.711 + // has a 'startup' method 1.712 + let syms = Object.keys(scope); 1.713 + if ((syms.length < 1) || 1.714 + (typeof scope[syms[0]].startup != "function")) { 1.715 + logger.warn("Provider " + url + " has no startup()"); 1.716 + AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()"); 1.717 + } 1.718 + logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource()); 1.719 + } 1.720 + catch (e) { 1.721 + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); 1.722 + logger.error("Exception loading default provider \"" + url + "\"", e); 1.723 + } 1.724 + }; 1.725 + } 1.726 + 1.727 + // Load any providers registered in the category manager 1.728 + let catman = Cc["@mozilla.org/categorymanager;1"]. 1.729 + getService(Ci.nsICategoryManager); 1.730 + let entries = catman.enumerateCategory(CATEGORY_PROVIDER_MODULE); 1.731 + while (entries.hasMoreElements()) { 1.732 + let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; 1.733 + let url = catman.getCategoryEntry(CATEGORY_PROVIDER_MODULE, entry); 1.734 + 1.735 + try { 1.736 + Components.utils.import(url, {}); 1.737 + } 1.738 + catch (e) { 1.739 + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); 1.740 + logger.error("Exception loading provider " + entry + " from category \"" + 1.741 + url + "\"", e); 1.742 + } 1.743 + } 1.744 + 1.745 + // Register our shutdown handler with the AsyncShutdown manager 1.746 + AsyncShutdown.profileBeforeChange.addBlocker("AddonManager: shutting down providers", 1.747 + this.shutdown.bind(this)); 1.748 + 1.749 + // Once we start calling providers we must allow all normal methods to work. 1.750 + gStarted = true; 1.751 + 1.752 + this.callProviders("startup", appChanged, oldAppVersion, 1.753 + oldPlatformVersion); 1.754 + 1.755 + // If this is a new profile just pretend that there were no changes 1.756 + if (appChanged === undefined) { 1.757 + for (let type in this.startupChanges) 1.758 + delete this.startupChanges[type]; 1.759 + } 1.760 + 1.761 + gStartupComplete = true; 1.762 + this.recordTimestamp("AMI_startup_end"); 1.763 + } 1.764 + catch (e) { 1.765 + logger.error("startup failed", e); 1.766 + AddonManagerPrivate.recordException("AMI", "startup failed", e); 1.767 + } 1.768 + }, 1.769 + 1.770 + /** 1.771 + * Registers a new AddonProvider. 1.772 + * 1.773 + * @param aProvider 1.774 + * The provider to register 1.775 + * @param aTypes 1.776 + * An optional array of add-on types 1.777 + */ 1.778 + registerProvider: function AMI_registerProvider(aProvider, aTypes) { 1.779 + if (!aProvider || typeof aProvider != "object") 1.780 + throw Components.Exception("aProvider must be specified", 1.781 + Cr.NS_ERROR_INVALID_ARG); 1.782 + 1.783 + if (aTypes && !Array.isArray(aTypes)) 1.784 + throw Components.Exception("aTypes must be an array or null", 1.785 + Cr.NS_ERROR_INVALID_ARG); 1.786 + 1.787 + this.providers.push(aProvider); 1.788 + 1.789 + if (aTypes) { 1.790 + aTypes.forEach(function(aType) { 1.791 + if (!(aType.id in this.types)) { 1.792 + if (!VALID_TYPES_REGEXP.test(aType.id)) { 1.793 + logger.warn("Ignoring invalid type " + aType.id); 1.794 + return; 1.795 + } 1.796 + 1.797 + this.types[aType.id] = { 1.798 + type: aType, 1.799 + providers: [aProvider] 1.800 + }; 1.801 + 1.802 + let typeListeners = this.typeListeners.slice(0); 1.803 + for (let listener of typeListeners) { 1.804 + safeCall(function listenerSafeCall() { 1.805 + listener.onTypeAdded(aType); 1.806 + }); 1.807 + } 1.808 + } 1.809 + else { 1.810 + this.types[aType.id].providers.push(aProvider); 1.811 + } 1.812 + }, this); 1.813 + } 1.814 + 1.815 + // If we're registering after startup call this provider's startup. 1.816 + if (gStarted) 1.817 + callProvider(aProvider, "startup"); 1.818 + }, 1.819 + 1.820 + /** 1.821 + * Unregisters an AddonProvider. 1.822 + * 1.823 + * @param aProvider 1.824 + * The provider to unregister 1.825 + */ 1.826 + unregisterProvider: function AMI_unregisterProvider(aProvider) { 1.827 + if (!aProvider || typeof aProvider != "object") 1.828 + throw Components.Exception("aProvider must be specified", 1.829 + Cr.NS_ERROR_INVALID_ARG); 1.830 + 1.831 + let pos = 0; 1.832 + while (pos < this.providers.length) { 1.833 + if (this.providers[pos] == aProvider) 1.834 + this.providers.splice(pos, 1); 1.835 + else 1.836 + pos++; 1.837 + } 1.838 + 1.839 + for (let type in this.types) { 1.840 + this.types[type].providers = this.types[type].providers.filter(function filterProvider(p) p != aProvider); 1.841 + if (this.types[type].providers.length == 0) { 1.842 + let oldType = this.types[type].type; 1.843 + delete this.types[type]; 1.844 + 1.845 + let typeListeners = this.typeListeners.slice(0); 1.846 + for (let listener of typeListeners) { 1.847 + safeCall(function listenerSafeCall() { 1.848 + listener.onTypeRemoved(oldType); 1.849 + }); 1.850 + } 1.851 + } 1.852 + } 1.853 + 1.854 + // If we're unregistering after startup call this provider's shutdown. 1.855 + if (gStarted) 1.856 + callProvider(aProvider, "shutdown"); 1.857 + }, 1.858 + 1.859 + /** 1.860 + * Calls a method on all registered providers if it exists and consumes any 1.861 + * thrown exception. Return values are ignored. Any parameters after the 1.862 + * method parameter are passed to the provider's method. 1.863 + * 1.864 + * @param aMethod 1.865 + * The method name to call 1.866 + * @see callProvider 1.867 + */ 1.868 + callProviders: function AMI_callProviders(aMethod, ...aArgs) { 1.869 + if (!aMethod || typeof aMethod != "string") 1.870 + throw Components.Exception("aMethod must be a non-empty string", 1.871 + Cr.NS_ERROR_INVALID_ARG); 1.872 + 1.873 + let providers = this.providers.slice(0); 1.874 + for (let provider of providers) { 1.875 + try { 1.876 + if (aMethod in provider) 1.877 + provider[aMethod].apply(provider, aArgs); 1.878 + } 1.879 + catch (e) { 1.880 + AddonManagerPrivate.recordException("AMI", "provider " + aMethod, e); 1.881 + logger.error("Exception calling provider " + aMethod, e); 1.882 + } 1.883 + } 1.884 + }, 1.885 + 1.886 + /** 1.887 + * Calls a method on all registered providers, if the provider implements 1.888 + * the method. The called method is expected to return a promise, and 1.889 + * callProvidersAsync returns a promise that resolves when every provider 1.890 + * method has either resolved or rejected. Rejection reasons are logged 1.891 + * but otherwise ignored. Return values are ignored. Any parameters after the 1.892 + * method parameter are passed to the provider's method. 1.893 + * 1.894 + * @param aMethod 1.895 + * The method name to call 1.896 + * @see callProvider 1.897 + */ 1.898 + callProvidersAsync: function AMI_callProviders(aMethod, ...aArgs) { 1.899 + if (!aMethod || typeof aMethod != "string") 1.900 + throw Components.Exception("aMethod must be a non-empty string", 1.901 + Cr.NS_ERROR_INVALID_ARG); 1.902 + 1.903 + let allProviders = []; 1.904 + 1.905 + let providers = this.providers.slice(0); 1.906 + for (let provider of providers) { 1.907 + try { 1.908 + if (aMethod in provider) { 1.909 + // Resolve a new promise with the result of the method, to handle both 1.910 + // methods that return values (or nothing) and methods that return promises. 1.911 + let providerResult = provider[aMethod].apply(provider, aArgs); 1.912 + let nextPromise = Promise.resolve(providerResult); 1.913 + // Log and swallow the errors from methods that do return promises. 1.914 + nextPromise = nextPromise.then( 1.915 + null, 1.916 + e => logger.error("Exception calling provider " + aMethod, e)); 1.917 + allProviders.push(nextPromise); 1.918 + } 1.919 + } 1.920 + catch (e) { 1.921 + logger.error("Exception calling provider " + aMethod, e); 1.922 + } 1.923 + } 1.924 + // Because we use promise.then to catch and log all errors above, Promise.all() 1.925 + // will never exit early because of a rejection. 1.926 + return Promise.all(allProviders); 1.927 + }, 1.928 + 1.929 + /** 1.930 + * Shuts down the addon manager and all registered providers, this must clean 1.931 + * up everything in order for automated tests to fake restarts. 1.932 + * @return Promise{null} that resolves when all providers and dependent modules 1.933 + * have finished shutting down 1.934 + */ 1.935 + shutdown: function AMI_shutdown() { 1.936 + logger.debug("shutdown"); 1.937 + // Clean up listeners 1.938 + Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this); 1.939 + Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this); 1.940 + Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this); 1.941 + Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this); 1.942 + Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this); 1.943 + Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this); 1.944 + 1.945 + // Only shut down providers if they've been started. Shut down 1.946 + // AddonRepository after providers (if any). 1.947 + let shuttingDown = null; 1.948 + if (gStarted) { 1.949 + shuttingDown = this.callProvidersAsync("shutdown") 1.950 + .then(null, 1.951 + err => logger.error("Failure during async provider shutdown", err)) 1.952 + .then(() => AddonRepository.shutdown()); 1.953 + } 1.954 + else { 1.955 + shuttingDown = AddonRepository.shutdown(); 1.956 + } 1.957 + 1.958 + shuttingDown.then(val => logger.debug("Async provider shutdown done"), 1.959 + err => logger.error("Failure during AddonRepository shutdown", err)) 1.960 + .then(() => { 1.961 + this.managerListeners.splice(0, this.managerListeners.length); 1.962 + this.installListeners.splice(0, this.installListeners.length); 1.963 + this.addonListeners.splice(0, this.addonListeners.length); 1.964 + this.typeListeners.splice(0, this.typeListeners.length); 1.965 + for (let type in this.startupChanges) 1.966 + delete this.startupChanges[type]; 1.967 + gStarted = false; 1.968 + gStartupComplete = false; 1.969 + }); 1.970 + return shuttingDown; 1.971 + }, 1.972 + 1.973 + /** 1.974 + * Notified when a preference we're interested in has changed. 1.975 + * 1.976 + * @see nsIObserver 1.977 + */ 1.978 + observe: function AMI_observe(aSubject, aTopic, aData) { 1.979 + switch (aData) { 1.980 + case PREF_EM_CHECK_COMPATIBILITY: { 1.981 + let oldValue = gCheckCompatibility; 1.982 + try { 1.983 + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); 1.984 + } catch(e) { 1.985 + gCheckCompatibility = true; 1.986 + } 1.987 + 1.988 + this.callManagerListeners("onCompatibilityModeChanged"); 1.989 + 1.990 + if (gCheckCompatibility != oldValue) 1.991 + this.updateAddonAppDisabledStates(); 1.992 + 1.993 + break; 1.994 + } 1.995 + case PREF_EM_STRICT_COMPATIBILITY: { 1.996 + let oldValue = gStrictCompatibility; 1.997 + try { 1.998 + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); 1.999 + } catch(e) { 1.1000 + gStrictCompatibility = true; 1.1001 + } 1.1002 + 1.1003 + this.callManagerListeners("onCompatibilityModeChanged"); 1.1004 + 1.1005 + if (gStrictCompatibility != oldValue) 1.1006 + this.updateAddonAppDisabledStates(); 1.1007 + 1.1008 + break; 1.1009 + } 1.1010 + case PREF_EM_CHECK_UPDATE_SECURITY: { 1.1011 + let oldValue = gCheckUpdateSecurity; 1.1012 + try { 1.1013 + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); 1.1014 + } catch(e) { 1.1015 + gCheckUpdateSecurity = true; 1.1016 + } 1.1017 + 1.1018 + this.callManagerListeners("onCheckUpdateSecurityChanged"); 1.1019 + 1.1020 + if (gCheckUpdateSecurity != oldValue) 1.1021 + this.updateAddonAppDisabledStates(); 1.1022 + 1.1023 + break; 1.1024 + } 1.1025 + case PREF_EM_UPDATE_ENABLED: { 1.1026 + let oldValue = gUpdateEnabled; 1.1027 + try { 1.1028 + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); 1.1029 + } catch(e) { 1.1030 + gUpdateEnabled = true; 1.1031 + } 1.1032 + 1.1033 + this.callManagerListeners("onUpdateModeChanged"); 1.1034 + break; 1.1035 + } 1.1036 + case PREF_EM_AUTOUPDATE_DEFAULT: { 1.1037 + let oldValue = gAutoUpdateDefault; 1.1038 + try { 1.1039 + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); 1.1040 + } catch(e) { 1.1041 + gAutoUpdateDefault = true; 1.1042 + } 1.1043 + 1.1044 + this.callManagerListeners("onUpdateModeChanged"); 1.1045 + break; 1.1046 + } 1.1047 + case PREF_EM_HOTFIX_ID: { 1.1048 + try { 1.1049 + gHotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID); 1.1050 + } catch(e) { 1.1051 + gHotfixID = null; 1.1052 + } 1.1053 + break; 1.1054 + } 1.1055 + } 1.1056 + }, 1.1057 + 1.1058 + /** 1.1059 + * Replaces %...% strings in an addon url (update and updateInfo) with 1.1060 + * appropriate values. 1.1061 + * 1.1062 + * @param aAddon 1.1063 + * The Addon representing the add-on 1.1064 + * @param aUri 1.1065 + * The string representation of the URI to escape 1.1066 + * @param aAppVersion 1.1067 + * The optional application version to use for %APP_VERSION% 1.1068 + * @return The appropriately escaped URI. 1.1069 + */ 1.1070 + escapeAddonURI: function AMI_escapeAddonURI(aAddon, aUri, aAppVersion) 1.1071 + { 1.1072 + if (!aAddon || typeof aAddon != "object") 1.1073 + throw Components.Exception("aAddon must be an Addon object", 1.1074 + Cr.NS_ERROR_INVALID_ARG); 1.1075 + 1.1076 + if (!aUri || typeof aUri != "string") 1.1077 + throw Components.Exception("aUri must be a non-empty string", 1.1078 + Cr.NS_ERROR_INVALID_ARG); 1.1079 + 1.1080 + if (aAppVersion && typeof aAppVersion != "string") 1.1081 + throw Components.Exception("aAppVersion must be a string or null", 1.1082 + Cr.NS_ERROR_INVALID_ARG); 1.1083 + 1.1084 + var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled" 1.1085 + : "userEnabled"; 1.1086 + 1.1087 + if (!aAddon.isCompatible) 1.1088 + addonStatus += ",incompatible"; 1.1089 + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) 1.1090 + addonStatus += ",blocklisted"; 1.1091 + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) 1.1092 + addonStatus += ",softblocked"; 1.1093 + 1.1094 + try { 1.1095 + var xpcomABI = Services.appinfo.XPCOMABI; 1.1096 + } catch (ex) { 1.1097 + xpcomABI = UNKNOWN_XPCOM_ABI; 1.1098 + } 1.1099 + 1.1100 + let uri = aUri.replace(/%ITEM_ID%/g, aAddon.id); 1.1101 + uri = uri.replace(/%ITEM_VERSION%/g, aAddon.version); 1.1102 + uri = uri.replace(/%ITEM_STATUS%/g, addonStatus); 1.1103 + uri = uri.replace(/%APP_ID%/g, Services.appinfo.ID); 1.1104 + uri = uri.replace(/%APP_VERSION%/g, aAppVersion ? aAppVersion : 1.1105 + Services.appinfo.version); 1.1106 + uri = uri.replace(/%REQ_VERSION%/g, UPDATE_REQUEST_VERSION); 1.1107 + uri = uri.replace(/%APP_OS%/g, Services.appinfo.OS); 1.1108 + uri = uri.replace(/%APP_ABI%/g, xpcomABI); 1.1109 + uri = uri.replace(/%APP_LOCALE%/g, getLocale()); 1.1110 + uri = uri.replace(/%CURRENT_APP_VERSION%/g, Services.appinfo.version); 1.1111 + 1.1112 + // Replace custom parameters (names of custom parameters must have at 1.1113 + // least 3 characters to prevent lookups for something like %D0%C8) 1.1114 + var catMan = null; 1.1115 + uri = uri.replace(/%(\w{3,})%/g, function parameterReplace(aMatch, aParam) { 1.1116 + if (!catMan) { 1.1117 + catMan = Cc["@mozilla.org/categorymanager;1"]. 1.1118 + getService(Ci.nsICategoryManager); 1.1119 + } 1.1120 + 1.1121 + try { 1.1122 + var contractID = catMan.getCategoryEntry(CATEGORY_UPDATE_PARAMS, aParam); 1.1123 + var paramHandler = Cc[contractID].getService(Ci.nsIPropertyBag2); 1.1124 + return paramHandler.getPropertyAsAString(aParam); 1.1125 + } 1.1126 + catch(e) { 1.1127 + return aMatch; 1.1128 + } 1.1129 + }); 1.1130 + 1.1131 + // escape() does not properly encode + symbols in any embedded FVF strings. 1.1132 + return uri.replace(/\+/g, "%2B"); 1.1133 + }, 1.1134 + 1.1135 + /** 1.1136 + * Performs a background update check by starting an update for all add-ons 1.1137 + * that can be updated. 1.1138 + */ 1.1139 + backgroundUpdateCheck: function AMI_backgroundUpdateCheck() { 1.1140 + if (!gStarted) 1.1141 + throw Components.Exception("AddonManager is not initialized", 1.1142 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1143 + 1.1144 + let hotfixID = this.hotfixID; 1.1145 + 1.1146 + let checkHotfix = hotfixID && 1.1147 + Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && 1.1148 + Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); 1.1149 + 1.1150 + if (!this.updateEnabled && !checkHotfix) 1.1151 + return; 1.1152 + 1.1153 + Services.obs.notifyObservers(null, "addons-background-update-start", null); 1.1154 + 1.1155 + // Start this from one to ensure the whole of this function completes before 1.1156 + // we can send the complete notification. Some parts can in some cases 1.1157 + // complete synchronously before later parts have a chance to increment 1.1158 + // pendingUpdates. 1.1159 + let pendingUpdates = 1; 1.1160 + 1.1161 + function notifyComplete() { 1.1162 + if (--pendingUpdates == 0) { 1.1163 + Services.obs.notifyObservers(null, 1.1164 + "addons-background-update-complete", 1.1165 + null); 1.1166 + } 1.1167 + } 1.1168 + 1.1169 + if (this.updateEnabled) { 1.1170 + let scope = {}; 1.1171 + Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope); 1.1172 + scope.LightweightThemeManager.updateCurrentTheme(); 1.1173 + 1.1174 + pendingUpdates++; 1.1175 + this.getAllAddons(function getAddonsCallback(aAddons) { 1.1176 + // If there is a known hotfix then exclude it from the list of add-ons to update. 1.1177 + var ids = [a.id for each (a in aAddons) if (a.id != hotfixID)]; 1.1178 + 1.1179 + // Repopulate repository cache first, to ensure compatibility overrides 1.1180 + // are up to date before checking for addon updates. 1.1181 + AddonRepository.backgroundUpdateCheck( 1.1182 + ids, function BUC_backgroundUpdateCheckCallback() { 1.1183 + pendingUpdates += aAddons.length; 1.1184 + aAddons.forEach(function BUC_forEachCallback(aAddon) { 1.1185 + if (aAddon.id == hotfixID) { 1.1186 + notifyComplete(); 1.1187 + return; 1.1188 + } 1.1189 + 1.1190 + // Check all add-ons for updates so that any compatibility updates will 1.1191 + // be applied 1.1192 + aAddon.findUpdates({ 1.1193 + onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) { 1.1194 + // Start installing updates when the add-on can be updated and 1.1195 + // background updates should be applied. 1.1196 + if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE && 1.1197 + AddonManager.shouldAutoUpdate(aAddon)) { 1.1198 + aInstall.install(); 1.1199 + } 1.1200 + }, 1.1201 + 1.1202 + onUpdateFinished: notifyComplete 1.1203 + }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE); 1.1204 + }); 1.1205 + 1.1206 + notifyComplete(); 1.1207 + }); 1.1208 + }); 1.1209 + } 1.1210 + 1.1211 + if (checkHotfix) { 1.1212 + var hotfixVersion = ""; 1.1213 + try { 1.1214 + hotfixVersion = Services.prefs.getCharPref(PREF_EM_HOTFIX_LASTVERSION); 1.1215 + } 1.1216 + catch (e) { } 1.1217 + 1.1218 + let url = null; 1.1219 + if (Services.prefs.getPrefType(PREF_EM_HOTFIX_URL) == Ci.nsIPrefBranch.PREF_STRING) 1.1220 + url = Services.prefs.getCharPref(PREF_EM_HOTFIX_URL); 1.1221 + else 1.1222 + url = Services.prefs.getCharPref(PREF_EM_UPDATE_BACKGROUND_URL); 1.1223 + 1.1224 + // Build the URI from a fake add-on data. 1.1225 + url = AddonManager.escapeAddonURI({ 1.1226 + id: hotfixID, 1.1227 + version: hotfixVersion, 1.1228 + userDisabled: false, 1.1229 + appDisabled: false 1.1230 + }, url); 1.1231 + 1.1232 + pendingUpdates++; 1.1233 + Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm"); 1.1234 + AddonUpdateChecker.checkForUpdates(hotfixID, null, url, { 1.1235 + onUpdateCheckComplete: function BUC_onUpdateCheckComplete(aUpdates) { 1.1236 + let update = AddonUpdateChecker.getNewestCompatibleUpdate(aUpdates); 1.1237 + if (!update) { 1.1238 + notifyComplete(); 1.1239 + return; 1.1240 + } 1.1241 + 1.1242 + // If the available version isn't newer than the last installed 1.1243 + // version then ignore it. 1.1244 + if (Services.vc.compare(hotfixVersion, update.version) >= 0) { 1.1245 + notifyComplete(); 1.1246 + return; 1.1247 + } 1.1248 + 1.1249 + logger.debug("Downloading hotfix version " + update.version); 1.1250 + AddonManager.getInstallForURL(update.updateURL, 1.1251 + function BUC_getInstallForURL(aInstall) { 1.1252 + aInstall.addListener({ 1.1253 + onDownloadEnded: function BUC_onDownloadEnded(aInstall) { 1.1254 + try { 1.1255 + if (!Services.prefs.getBoolPref(PREF_EM_CERT_CHECKATTRIBUTES)) 1.1256 + return; 1.1257 + } 1.1258 + catch (e) { 1.1259 + // By default don't do certificate checks. 1.1260 + return; 1.1261 + } 1.1262 + 1.1263 + try { 1.1264 + CertUtils.validateCert(aInstall.certificate, 1.1265 + CertUtils.readCertPrefs(PREF_EM_HOTFIX_CERTS)); 1.1266 + } 1.1267 + catch (e) { 1.1268 + logger.warn("The hotfix add-on was not signed by the expected " + 1.1269 + "certificate and so will not be installed."); 1.1270 + aInstall.cancel(); 1.1271 + } 1.1272 + }, 1.1273 + 1.1274 + onInstallEnded: function BUC_onInstallEnded(aInstall) { 1.1275 + // Remember the last successfully installed version. 1.1276 + Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, 1.1277 + aInstall.version); 1.1278 + }, 1.1279 + 1.1280 + onInstallCancelled: function BUC_onInstallCancelled(aInstall) { 1.1281 + // Revert to the previous version if the installation was 1.1282 + // cancelled. 1.1283 + Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION, 1.1284 + hotfixVersion); 1.1285 + } 1.1286 + }); 1.1287 + 1.1288 + aInstall.install(); 1.1289 + 1.1290 + notifyComplete(); 1.1291 + }, "application/x-xpinstall", update.updateHash, null, 1.1292 + null, update.version); 1.1293 + }, 1.1294 + 1.1295 + onUpdateCheckError: notifyComplete 1.1296 + }); 1.1297 + } 1.1298 + 1.1299 + notifyComplete(); 1.1300 + }, 1.1301 + 1.1302 + /** 1.1303 + * Adds a add-on to the list of detected changes for this startup. If 1.1304 + * addStartupChange is called multiple times for the same add-on in the same 1.1305 + * startup then only the most recent change will be remembered. 1.1306 + * 1.1307 + * @param aType 1.1308 + * The type of change as a string. Providers can define their own 1.1309 + * types of changes or use the existing defined STARTUP_CHANGE_* 1.1310 + * constants 1.1311 + * @param aID 1.1312 + * The ID of the add-on 1.1313 + */ 1.1314 + addStartupChange: function AMI_addStartupChange(aType, aID) { 1.1315 + if (!aType || typeof aType != "string") 1.1316 + throw Components.Exception("aType must be a non-empty string", 1.1317 + Cr.NS_ERROR_INVALID_ARG); 1.1318 + 1.1319 + if (!aID || typeof aID != "string") 1.1320 + throw Components.Exception("aID must be a non-empty string", 1.1321 + Cr.NS_ERROR_INVALID_ARG); 1.1322 + 1.1323 + if (gStartupComplete) 1.1324 + return; 1.1325 + 1.1326 + // Ensure that an ID is only listed in one type of change 1.1327 + for (let type in this.startupChanges) 1.1328 + this.removeStartupChange(type, aID); 1.1329 + 1.1330 + if (!(aType in this.startupChanges)) 1.1331 + this.startupChanges[aType] = []; 1.1332 + this.startupChanges[aType].push(aID); 1.1333 + }, 1.1334 + 1.1335 + /** 1.1336 + * Removes a startup change for an add-on. 1.1337 + * 1.1338 + * @param aType 1.1339 + * The type of change 1.1340 + * @param aID 1.1341 + * The ID of the add-on 1.1342 + */ 1.1343 + removeStartupChange: function AMI_removeStartupChange(aType, aID) { 1.1344 + if (!aType || typeof aType != "string") 1.1345 + throw Components.Exception("aType must be a non-empty string", 1.1346 + Cr.NS_ERROR_INVALID_ARG); 1.1347 + 1.1348 + if (!aID || typeof aID != "string") 1.1349 + throw Components.Exception("aID must be a non-empty string", 1.1350 + Cr.NS_ERROR_INVALID_ARG); 1.1351 + 1.1352 + if (gStartupComplete) 1.1353 + return; 1.1354 + 1.1355 + if (!(aType in this.startupChanges)) 1.1356 + return; 1.1357 + 1.1358 + this.startupChanges[aType] = this.startupChanges[aType].filter( 1.1359 + function filterItem(aItem) aItem != aID); 1.1360 + }, 1.1361 + 1.1362 + /** 1.1363 + * Calls all registered AddonManagerListeners with an event. Any parameters 1.1364 + * after the method parameter are passed to the listener. 1.1365 + * 1.1366 + * @param aMethod 1.1367 + * The method on the listeners to call 1.1368 + */ 1.1369 + callManagerListeners: function AMI_callManagerListeners(aMethod, ...aArgs) { 1.1370 + if (!gStarted) 1.1371 + throw Components.Exception("AddonManager is not initialized", 1.1372 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1373 + 1.1374 + if (!aMethod || typeof aMethod != "string") 1.1375 + throw Components.Exception("aMethod must be a non-empty string", 1.1376 + Cr.NS_ERROR_INVALID_ARG); 1.1377 + 1.1378 + let managerListeners = this.managerListeners.slice(0); 1.1379 + for (let listener of managerListeners) { 1.1380 + try { 1.1381 + if (aMethod in listener) 1.1382 + listener[aMethod].apply(listener, aArgs); 1.1383 + } 1.1384 + catch (e) { 1.1385 + logger.warn("AddonManagerListener threw exception when calling " + aMethod, e); 1.1386 + } 1.1387 + } 1.1388 + }, 1.1389 + 1.1390 + /** 1.1391 + * Calls all registered InstallListeners with an event. Any parameters after 1.1392 + * the extraListeners parameter are passed to the listener. 1.1393 + * 1.1394 + * @param aMethod 1.1395 + * The method on the listeners to call 1.1396 + * @param aExtraListeners 1.1397 + * An optional array of extra InstallListeners to also call 1.1398 + * @return false if any of the listeners returned false, true otherwise 1.1399 + */ 1.1400 + callInstallListeners: function AMI_callInstallListeners(aMethod, 1.1401 + aExtraListeners, ...aArgs) { 1.1402 + if (!gStarted) 1.1403 + throw Components.Exception("AddonManager is not initialized", 1.1404 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1405 + 1.1406 + if (!aMethod || typeof aMethod != "string") 1.1407 + throw Components.Exception("aMethod must be a non-empty string", 1.1408 + Cr.NS_ERROR_INVALID_ARG); 1.1409 + 1.1410 + if (aExtraListeners && !Array.isArray(aExtraListeners)) 1.1411 + throw Components.Exception("aExtraListeners must be an array or null", 1.1412 + Cr.NS_ERROR_INVALID_ARG); 1.1413 + 1.1414 + let result = true; 1.1415 + let listeners; 1.1416 + if (aExtraListeners) 1.1417 + listeners = aExtraListeners.concat(this.installListeners); 1.1418 + else 1.1419 + listeners = this.installListeners.slice(0); 1.1420 + 1.1421 + for (let listener of listeners) { 1.1422 + try { 1.1423 + if (aMethod in listener) { 1.1424 + if (listener[aMethod].apply(listener, aArgs) === false) 1.1425 + result = false; 1.1426 + } 1.1427 + } 1.1428 + catch (e) { 1.1429 + logger.warn("InstallListener threw exception when calling " + aMethod, e); 1.1430 + } 1.1431 + } 1.1432 + return result; 1.1433 + }, 1.1434 + 1.1435 + /** 1.1436 + * Calls all registered AddonListeners with an event. Any parameters after 1.1437 + * the method parameter are passed to the listener. 1.1438 + * 1.1439 + * @param aMethod 1.1440 + * The method on the listeners to call 1.1441 + */ 1.1442 + callAddonListeners: function AMI_callAddonListeners(aMethod, ...aArgs) { 1.1443 + if (!gStarted) 1.1444 + throw Components.Exception("AddonManager is not initialized", 1.1445 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1446 + 1.1447 + if (!aMethod || typeof aMethod != "string") 1.1448 + throw Components.Exception("aMethod must be a non-empty string", 1.1449 + Cr.NS_ERROR_INVALID_ARG); 1.1450 + 1.1451 + let addonListeners = this.addonListeners.slice(0); 1.1452 + for (let listener of addonListeners) { 1.1453 + try { 1.1454 + if (aMethod in listener) 1.1455 + listener[aMethod].apply(listener, aArgs); 1.1456 + } 1.1457 + catch (e) { 1.1458 + logger.warn("AddonListener threw exception when calling " + aMethod, e); 1.1459 + } 1.1460 + } 1.1461 + }, 1.1462 + 1.1463 + /** 1.1464 + * Notifies all providers that an add-on has been enabled when that type of 1.1465 + * add-on only supports a single add-on being enabled at a time. This allows 1.1466 + * the providers to disable theirs if necessary. 1.1467 + * 1.1468 + * @param aID 1.1469 + * The ID of the enabled add-on 1.1470 + * @param aType 1.1471 + * The type of the enabled add-on 1.1472 + * @param aPendingRestart 1.1473 + * A boolean indicating if the change will only take place the next 1.1474 + * time the application is restarted 1.1475 + */ 1.1476 + notifyAddonChanged: function AMI_notifyAddonChanged(aID, aType, aPendingRestart) { 1.1477 + if (!gStarted) 1.1478 + throw Components.Exception("AddonManager is not initialized", 1.1479 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1480 + 1.1481 + if (aID && typeof aID != "string") 1.1482 + throw Components.Exception("aID must be a string or null", 1.1483 + Cr.NS_ERROR_INVALID_ARG); 1.1484 + 1.1485 + if (!aType || typeof aType != "string") 1.1486 + throw Components.Exception("aType must be a non-empty string", 1.1487 + Cr.NS_ERROR_INVALID_ARG); 1.1488 + 1.1489 + this.callProviders("addonChanged", aID, aType, aPendingRestart); 1.1490 + }, 1.1491 + 1.1492 + /** 1.1493 + * Notifies all providers they need to update the appDisabled property for 1.1494 + * their add-ons in response to an application change such as a blocklist 1.1495 + * update. 1.1496 + */ 1.1497 + updateAddonAppDisabledStates: function AMI_updateAddonAppDisabledStates() { 1.1498 + if (!gStarted) 1.1499 + throw Components.Exception("AddonManager is not initialized", 1.1500 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1501 + 1.1502 + this.callProviders("updateAddonAppDisabledStates"); 1.1503 + }, 1.1504 + 1.1505 + /** 1.1506 + * Notifies all providers that the repository has updated its data for 1.1507 + * installed add-ons. 1.1508 + * 1.1509 + * @param aCallback 1.1510 + * Function to call when operation is complete. 1.1511 + */ 1.1512 + updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) { 1.1513 + if (!gStarted) 1.1514 + throw Components.Exception("AddonManager is not initialized", 1.1515 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1516 + 1.1517 + if (typeof aCallback != "function") 1.1518 + throw Components.Exception("aCallback must be a function", 1.1519 + Cr.NS_ERROR_INVALID_ARG); 1.1520 + 1.1521 + new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", { 1.1522 + nextObject: function updateAddonRepositoryData_nextObject(aCaller, aProvider) { 1.1523 + callProvider(aProvider, 1.1524 + "updateAddonRepositoryData", 1.1525 + null, 1.1526 + aCaller.callNext.bind(aCaller)); 1.1527 + }, 1.1528 + noMoreObjects: function updateAddonRepositoryData_noMoreObjects(aCaller) { 1.1529 + safeCall(aCallback); 1.1530 + // only tests should care about this 1.1531 + Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null); 1.1532 + } 1.1533 + }); 1.1534 + }, 1.1535 + 1.1536 + /** 1.1537 + * Asynchronously gets an AddonInstall for a URL. 1.1538 + * 1.1539 + * @param aUrl 1.1540 + * The string represenation of the URL the add-on is located at 1.1541 + * @param aCallback 1.1542 + * A callback to pass the AddonInstall to 1.1543 + * @param aMimetype 1.1544 + * The mimetype of the add-on 1.1545 + * @param aHash 1.1546 + * An optional hash of the add-on 1.1547 + * @param aName 1.1548 + * An optional placeholder name while the add-on is being downloaded 1.1549 + * @param aIcons 1.1550 + * Optional placeholder icons while the add-on is being downloaded 1.1551 + * @param aVersion 1.1552 + * An optional placeholder version while the add-on is being downloaded 1.1553 + * @param aLoadGroup 1.1554 + * An optional nsILoadGroup to associate any network requests with 1.1555 + * @throws if the aUrl, aCallback or aMimetype arguments are not specified 1.1556 + */ 1.1557 + getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype, 1.1558 + aHash, aName, aIcons, 1.1559 + aVersion, aLoadGroup) { 1.1560 + if (!gStarted) 1.1561 + throw Components.Exception("AddonManager is not initialized", 1.1562 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1563 + 1.1564 + if (!aUrl || typeof aUrl != "string") 1.1565 + throw Components.Exception("aURL must be a non-empty string", 1.1566 + Cr.NS_ERROR_INVALID_ARG); 1.1567 + 1.1568 + if (typeof aCallback != "function") 1.1569 + throw Components.Exception("aCallback must be a function", 1.1570 + Cr.NS_ERROR_INVALID_ARG); 1.1571 + 1.1572 + if (!aMimetype || typeof aMimetype != "string") 1.1573 + throw Components.Exception("aMimetype must be a non-empty string", 1.1574 + Cr.NS_ERROR_INVALID_ARG); 1.1575 + 1.1576 + if (aHash && typeof aHash != "string") 1.1577 + throw Components.Exception("aHash must be a string or null", 1.1578 + Cr.NS_ERROR_INVALID_ARG); 1.1579 + 1.1580 + if (aName && typeof aName != "string") 1.1581 + throw Components.Exception("aName must be a string or null", 1.1582 + Cr.NS_ERROR_INVALID_ARG); 1.1583 + 1.1584 + if (aIcons) { 1.1585 + if (typeof aIcons == "string") 1.1586 + aIcons = { "32": aIcons }; 1.1587 + else if (typeof aIcons != "object") 1.1588 + throw Components.Exception("aIcons must be a string, an object or null", 1.1589 + Cr.NS_ERROR_INVALID_ARG); 1.1590 + } else { 1.1591 + aIcons = {}; 1.1592 + } 1.1593 + 1.1594 + if (aVersion && typeof aVersion != "string") 1.1595 + throw Components.Exception("aVersion must be a string or null", 1.1596 + Cr.NS_ERROR_INVALID_ARG); 1.1597 + 1.1598 + if (aLoadGroup && (!(aLoadGroup instanceof Ci.nsILoadGroup))) 1.1599 + throw Components.Exception("aLoadGroup must be a nsILoadGroup or null", 1.1600 + Cr.NS_ERROR_INVALID_ARG); 1.1601 + 1.1602 + let providers = this.providers.slice(0); 1.1603 + for (let provider of providers) { 1.1604 + if (callProvider(provider, "supportsMimetype", false, aMimetype)) { 1.1605 + callProvider(provider, "getInstallForURL", null, 1.1606 + aUrl, aHash, aName, aIcons, aVersion, aLoadGroup, 1.1607 + function getInstallForURL_safeCall(aInstall) { 1.1608 + safeCall(aCallback, aInstall); 1.1609 + }); 1.1610 + return; 1.1611 + } 1.1612 + } 1.1613 + safeCall(aCallback, null); 1.1614 + }, 1.1615 + 1.1616 + /** 1.1617 + * Asynchronously gets an AddonInstall for an nsIFile. 1.1618 + * 1.1619 + * @param aFile 1.1620 + * The nsIFile where the add-on is located 1.1621 + * @param aCallback 1.1622 + * A callback to pass the AddonInstall to 1.1623 + * @param aMimetype 1.1624 + * An optional mimetype hint for the add-on 1.1625 + * @throws if the aFile or aCallback arguments are not specified 1.1626 + */ 1.1627 + getInstallForFile: function AMI_getInstallForFile(aFile, aCallback, aMimetype) { 1.1628 + if (!gStarted) 1.1629 + throw Components.Exception("AddonManager is not initialized", 1.1630 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1631 + 1.1632 + if (!(aFile instanceof Ci.nsIFile)) 1.1633 + throw Components.Exception("aFile must be a nsIFile", 1.1634 + Cr.NS_ERROR_INVALID_ARG); 1.1635 + 1.1636 + if (typeof aCallback != "function") 1.1637 + throw Components.Exception("aCallback must be a function", 1.1638 + Cr.NS_ERROR_INVALID_ARG); 1.1639 + 1.1640 + if (aMimetype && typeof aMimetype != "string") 1.1641 + throw Components.Exception("aMimetype must be a string or null", 1.1642 + Cr.NS_ERROR_INVALID_ARG); 1.1643 + 1.1644 + new AsyncObjectCaller(this.providers, "getInstallForFile", { 1.1645 + nextObject: function getInstallForFile_nextObject(aCaller, aProvider) { 1.1646 + callProvider(aProvider, "getInstallForFile", null, aFile, 1.1647 + function getInstallForFile_safeCall(aInstall) { 1.1648 + if (aInstall) 1.1649 + safeCall(aCallback, aInstall); 1.1650 + else 1.1651 + aCaller.callNext(); 1.1652 + }); 1.1653 + }, 1.1654 + 1.1655 + noMoreObjects: function getInstallForFile_noMoreObjects(aCaller) { 1.1656 + safeCall(aCallback, null); 1.1657 + } 1.1658 + }); 1.1659 + }, 1.1660 + 1.1661 + /** 1.1662 + * Asynchronously gets all current AddonInstalls optionally limiting to a list 1.1663 + * of types. 1.1664 + * 1.1665 + * @param aTypes 1.1666 + * An optional array of types to retrieve. Each type is a string name 1.1667 + * @param aCallback 1.1668 + * A callback which will be passed an array of AddonInstalls 1.1669 + * @throws If the aCallback argument is not specified 1.1670 + */ 1.1671 + getInstallsByTypes: function AMI_getInstallsByTypes(aTypes, aCallback) { 1.1672 + if (!gStarted) 1.1673 + throw Components.Exception("AddonManager is not initialized", 1.1674 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1675 + 1.1676 + if (aTypes && !Array.isArray(aTypes)) 1.1677 + throw Components.Exception("aTypes must be an array or null", 1.1678 + Cr.NS_ERROR_INVALID_ARG); 1.1679 + 1.1680 + if (typeof aCallback != "function") 1.1681 + throw Components.Exception("aCallback must be a function", 1.1682 + Cr.NS_ERROR_INVALID_ARG); 1.1683 + 1.1684 + let installs = []; 1.1685 + 1.1686 + new AsyncObjectCaller(this.providers, "getInstallsByTypes", { 1.1687 + nextObject: function getInstallsByTypes_nextObject(aCaller, aProvider) { 1.1688 + callProvider(aProvider, "getInstallsByTypes", null, aTypes, 1.1689 + function getInstallsByTypes_safeCall(aProviderInstalls) { 1.1690 + installs = installs.concat(aProviderInstalls); 1.1691 + aCaller.callNext(); 1.1692 + }); 1.1693 + }, 1.1694 + 1.1695 + noMoreObjects: function getInstallsByTypes_noMoreObjects(aCaller) { 1.1696 + safeCall(aCallback, installs); 1.1697 + } 1.1698 + }); 1.1699 + }, 1.1700 + 1.1701 + /** 1.1702 + * Asynchronously gets all current AddonInstalls. 1.1703 + * 1.1704 + * @param aCallback 1.1705 + * A callback which will be passed an array of AddonInstalls 1.1706 + */ 1.1707 + getAllInstalls: function AMI_getAllInstalls(aCallback) { 1.1708 + if (!gStarted) 1.1709 + throw Components.Exception("AddonManager is not initialized", 1.1710 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1711 + 1.1712 + this.getInstallsByTypes(null, aCallback); 1.1713 + }, 1.1714 + 1.1715 + /** 1.1716 + * Synchronously map a URI to the corresponding Addon ID. 1.1717 + * 1.1718 + * Mappable URIs are limited to in-application resources belonging to the 1.1719 + * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. 1.1720 + * but do not include URIs from meta data, such as the add-on homepage. 1.1721 + * 1.1722 + * @param aURI 1.1723 + * nsIURI to map to an addon id 1.1724 + * @return string containing the Addon ID or null 1.1725 + * @see amIAddonManager.mapURIToAddonID 1.1726 + */ 1.1727 + mapURIToAddonID: function AMI_mapURIToAddonID(aURI) { 1.1728 + if (!(aURI instanceof Ci.nsIURI)) { 1.1729 + throw Components.Exception("aURI is not a nsIURI", 1.1730 + Cr.NS_ERROR_INVALID_ARG); 1.1731 + } 1.1732 + // Try all providers 1.1733 + let providers = this.providers.slice(0); 1.1734 + for (let provider of providers) { 1.1735 + var id = callProvider(provider, "mapURIToAddonID", null, aURI); 1.1736 + if (id !== null) { 1.1737 + return id; 1.1738 + } 1.1739 + } 1.1740 + 1.1741 + return null; 1.1742 + }, 1.1743 + 1.1744 + /** 1.1745 + * Checks whether installation is enabled for a particular mimetype. 1.1746 + * 1.1747 + * @param aMimetype 1.1748 + * The mimetype to check 1.1749 + * @return true if installation is enabled for the mimetype 1.1750 + */ 1.1751 + isInstallEnabled: function AMI_isInstallEnabled(aMimetype) { 1.1752 + if (!gStarted) 1.1753 + throw Components.Exception("AddonManager is not initialized", 1.1754 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1755 + 1.1756 + if (!aMimetype || typeof aMimetype != "string") 1.1757 + throw Components.Exception("aMimetype must be a non-empty string", 1.1758 + Cr.NS_ERROR_INVALID_ARG); 1.1759 + 1.1760 + let providers = this.providers.slice(0); 1.1761 + for (let provider of providers) { 1.1762 + if (callProvider(provider, "supportsMimetype", false, aMimetype) && 1.1763 + callProvider(provider, "isInstallEnabled")) 1.1764 + return true; 1.1765 + } 1.1766 + return false; 1.1767 + }, 1.1768 + 1.1769 + /** 1.1770 + * Checks whether a particular source is allowed to install add-ons of a 1.1771 + * given mimetype. 1.1772 + * 1.1773 + * @param aMimetype 1.1774 + * The mimetype of the add-on 1.1775 + * @param aURI 1.1776 + * The optional nsIURI of the source 1.1777 + * @return true if the source is allowed to install this mimetype 1.1778 + */ 1.1779 + isInstallAllowed: function AMI_isInstallAllowed(aMimetype, aURI) { 1.1780 + if (!gStarted) 1.1781 + throw Components.Exception("AddonManager is not initialized", 1.1782 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1783 + 1.1784 + if (!aMimetype || typeof aMimetype != "string") 1.1785 + throw Components.Exception("aMimetype must be a non-empty string", 1.1786 + Cr.NS_ERROR_INVALID_ARG); 1.1787 + 1.1788 + if (aURI && !(aURI instanceof Ci.nsIURI)) 1.1789 + throw Components.Exception("aURI must be a nsIURI or null", 1.1790 + Cr.NS_ERROR_INVALID_ARG); 1.1791 + 1.1792 + let providers = this.providers.slice(0); 1.1793 + for (let provider of providers) { 1.1794 + if (callProvider(provider, "supportsMimetype", false, aMimetype) && 1.1795 + callProvider(provider, "isInstallAllowed", null, aURI)) 1.1796 + return true; 1.1797 + } 1.1798 + return false; 1.1799 + }, 1.1800 + 1.1801 + /** 1.1802 + * Starts installation of an array of AddonInstalls notifying the registered 1.1803 + * web install listener of blocked or started installs. 1.1804 + * 1.1805 + * @param aMimetype 1.1806 + * The mimetype of add-ons being installed 1.1807 + * @param aSource 1.1808 + * The optional nsIDOMWindow that started the installs 1.1809 + * @param aURI 1.1810 + * The optional nsIURI that started the installs 1.1811 + * @param aInstalls 1.1812 + * The array of AddonInstalls to be installed 1.1813 + */ 1.1814 + installAddonsFromWebpage: function AMI_installAddonsFromWebpage(aMimetype, 1.1815 + aSource, 1.1816 + aURI, 1.1817 + aInstalls) { 1.1818 + if (!gStarted) 1.1819 + throw Components.Exception("AddonManager is not initialized", 1.1820 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1821 + 1.1822 + if (!aMimetype || typeof aMimetype != "string") 1.1823 + throw Components.Exception("aMimetype must be a non-empty string", 1.1824 + Cr.NS_ERROR_INVALID_ARG); 1.1825 + 1.1826 + if (aSource && !(aSource instanceof Ci.nsIDOMWindow)) 1.1827 + throw Components.Exception("aSource must be a nsIDOMWindow or null", 1.1828 + Cr.NS_ERROR_INVALID_ARG); 1.1829 + 1.1830 + if (aURI && !(aURI instanceof Ci.nsIURI)) 1.1831 + throw Components.Exception("aURI must be a nsIURI or null", 1.1832 + Cr.NS_ERROR_INVALID_ARG); 1.1833 + 1.1834 + if (!Array.isArray(aInstalls)) 1.1835 + throw Components.Exception("aInstalls must be an array", 1.1836 + Cr.NS_ERROR_INVALID_ARG); 1.1837 + 1.1838 + if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) { 1.1839 + logger.warn("No web installer available, cancelling all installs"); 1.1840 + aInstalls.forEach(function(aInstall) { 1.1841 + aInstall.cancel(); 1.1842 + }); 1.1843 + return; 1.1844 + } 1.1845 + 1.1846 + try { 1.1847 + let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]. 1.1848 + getService(Ci.amIWebInstallListener); 1.1849 + 1.1850 + if (!this.isInstallEnabled(aMimetype, aURI)) { 1.1851 + weblistener.onWebInstallDisabled(aSource, aURI, aInstalls, 1.1852 + aInstalls.length); 1.1853 + } 1.1854 + else if (!this.isInstallAllowed(aMimetype, aURI)) { 1.1855 + if (weblistener.onWebInstallBlocked(aSource, aURI, aInstalls, 1.1856 + aInstalls.length)) { 1.1857 + aInstalls.forEach(function(aInstall) { 1.1858 + aInstall.install(); 1.1859 + }); 1.1860 + } 1.1861 + } 1.1862 + else if (weblistener.onWebInstallRequested(aSource, aURI, aInstalls, 1.1863 + aInstalls.length)) { 1.1864 + aInstalls.forEach(function(aInstall) { 1.1865 + aInstall.install(); 1.1866 + }); 1.1867 + } 1.1868 + } 1.1869 + catch (e) { 1.1870 + // In the event that the weblistener throws during instantiation or when 1.1871 + // calling onWebInstallBlocked or onWebInstallRequested all of the 1.1872 + // installs should get cancelled. 1.1873 + logger.warn("Failure calling web installer", e); 1.1874 + aInstalls.forEach(function(aInstall) { 1.1875 + aInstall.cancel(); 1.1876 + }); 1.1877 + } 1.1878 + }, 1.1879 + 1.1880 + /** 1.1881 + * Adds a new InstallListener if the listener is not already registered. 1.1882 + * 1.1883 + * @param aListener 1.1884 + * The InstallListener to add 1.1885 + */ 1.1886 + addInstallListener: function AMI_addInstallListener(aListener) { 1.1887 + if (!aListener || typeof aListener != "object") 1.1888 + throw Components.Exception("aListener must be a InstallListener object", 1.1889 + Cr.NS_ERROR_INVALID_ARG); 1.1890 + 1.1891 + if (!this.installListeners.some(function addInstallListener_matchListener(i) { 1.1892 + return i == aListener; })) 1.1893 + this.installListeners.push(aListener); 1.1894 + }, 1.1895 + 1.1896 + /** 1.1897 + * Removes an InstallListener if the listener is registered. 1.1898 + * 1.1899 + * @param aListener 1.1900 + * The InstallListener to remove 1.1901 + */ 1.1902 + removeInstallListener: function AMI_removeInstallListener(aListener) { 1.1903 + if (!aListener || typeof aListener != "object") 1.1904 + throw Components.Exception("aListener must be a InstallListener object", 1.1905 + Cr.NS_ERROR_INVALID_ARG); 1.1906 + 1.1907 + let pos = 0; 1.1908 + while (pos < this.installListeners.length) { 1.1909 + if (this.installListeners[pos] == aListener) 1.1910 + this.installListeners.splice(pos, 1); 1.1911 + else 1.1912 + pos++; 1.1913 + } 1.1914 + }, 1.1915 + 1.1916 + /** 1.1917 + * Asynchronously gets an add-on with a specific ID. 1.1918 + * 1.1919 + * @param aID 1.1920 + * The ID of the add-on to retrieve 1.1921 + * @param aCallback 1.1922 + * The callback to pass the retrieved add-on to 1.1923 + * @throws if the aID or aCallback arguments are not specified 1.1924 + */ 1.1925 + getAddonByID: function AMI_getAddonByID(aID, aCallback) { 1.1926 + if (!gStarted) 1.1927 + throw Components.Exception("AddonManager is not initialized", 1.1928 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1929 + 1.1930 + if (!aID || typeof aID != "string") 1.1931 + throw Components.Exception("aID must be a non-empty string", 1.1932 + Cr.NS_ERROR_INVALID_ARG); 1.1933 + 1.1934 + if (typeof aCallback != "function") 1.1935 + throw Components.Exception("aCallback must be a function", 1.1936 + Cr.NS_ERROR_INVALID_ARG); 1.1937 + 1.1938 + new AsyncObjectCaller(this.providers, "getAddonByID", { 1.1939 + nextObject: function getAddonByID_nextObject(aCaller, aProvider) { 1.1940 + callProvider(aProvider, "getAddonByID", null, aID, 1.1941 + function getAddonByID_safeCall(aAddon) { 1.1942 + if (aAddon) 1.1943 + safeCall(aCallback, aAddon); 1.1944 + else 1.1945 + aCaller.callNext(); 1.1946 + }); 1.1947 + }, 1.1948 + 1.1949 + noMoreObjects: function getAddonByID_noMoreObjects(aCaller) { 1.1950 + safeCall(aCallback, null); 1.1951 + } 1.1952 + }); 1.1953 + }, 1.1954 + 1.1955 + /** 1.1956 + * Asynchronously get an add-on with a specific Sync GUID. 1.1957 + * 1.1958 + * @param aGUID 1.1959 + * String GUID of add-on to retrieve 1.1960 + * @param aCallback 1.1961 + * The callback to pass the retrieved add-on to. 1.1962 + * @throws if the aGUID or aCallback arguments are not specified 1.1963 + */ 1.1964 + getAddonBySyncGUID: function AMI_getAddonBySyncGUID(aGUID, aCallback) { 1.1965 + if (!gStarted) 1.1966 + throw Components.Exception("AddonManager is not initialized", 1.1967 + Cr.NS_ERROR_NOT_INITIALIZED); 1.1968 + 1.1969 + if (!aGUID || typeof aGUID != "string") 1.1970 + throw Components.Exception("aGUID must be a non-empty string", 1.1971 + Cr.NS_ERROR_INVALID_ARG); 1.1972 + 1.1973 + if (typeof aCallback != "function") 1.1974 + throw Components.Exception("aCallback must be a function", 1.1975 + Cr.NS_ERROR_INVALID_ARG); 1.1976 + 1.1977 + new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", { 1.1978 + nextObject: function getAddonBySyncGUID_nextObject(aCaller, aProvider) { 1.1979 + callProvider(aProvider, "getAddonBySyncGUID", null, aGUID, 1.1980 + function getAddonBySyncGUID_safeCall(aAddon) { 1.1981 + if (aAddon) { 1.1982 + safeCall(aCallback, aAddon); 1.1983 + } else { 1.1984 + aCaller.callNext(); 1.1985 + } 1.1986 + }); 1.1987 + }, 1.1988 + 1.1989 + noMoreObjects: function getAddonBySyncGUID_noMoreObjects(aCaller) { 1.1990 + safeCall(aCallback, null); 1.1991 + } 1.1992 + }); 1.1993 + }, 1.1994 + 1.1995 + /** 1.1996 + * Asynchronously gets an array of add-ons. 1.1997 + * 1.1998 + * @param aIDs 1.1999 + * The array of IDs to retrieve 1.2000 + * @param aCallback 1.2001 + * The callback to pass an array of Addons to 1.2002 + * @throws if the aID or aCallback arguments are not specified 1.2003 + */ 1.2004 + getAddonsByIDs: function AMI_getAddonsByIDs(aIDs, aCallback) { 1.2005 + if (!gStarted) 1.2006 + throw Components.Exception("AddonManager is not initialized", 1.2007 + Cr.NS_ERROR_NOT_INITIALIZED); 1.2008 + 1.2009 + if (!Array.isArray(aIDs)) 1.2010 + throw Components.Exception("aIDs must be an array", 1.2011 + Cr.NS_ERROR_INVALID_ARG); 1.2012 + 1.2013 + if (typeof aCallback != "function") 1.2014 + throw Components.Exception("aCallback must be a function", 1.2015 + Cr.NS_ERROR_INVALID_ARG); 1.2016 + 1.2017 + let addons = []; 1.2018 + 1.2019 + new AsyncObjectCaller(aIDs, null, { 1.2020 + nextObject: function getAddonsByIDs_nextObject(aCaller, aID) { 1.2021 + AddonManagerInternal.getAddonByID(aID, 1.2022 + function getAddonsByIDs_getAddonByID(aAddon) { 1.2023 + addons.push(aAddon); 1.2024 + aCaller.callNext(); 1.2025 + }); 1.2026 + }, 1.2027 + 1.2028 + noMoreObjects: function getAddonsByIDs_noMoreObjects(aCaller) { 1.2029 + safeCall(aCallback, addons); 1.2030 + } 1.2031 + }); 1.2032 + }, 1.2033 + 1.2034 + /** 1.2035 + * Asynchronously gets add-ons of specific types. 1.2036 + * 1.2037 + * @param aTypes 1.2038 + * An optional array of types to retrieve. Each type is a string name 1.2039 + * @param aCallback 1.2040 + * The callback to pass an array of Addons to. 1.2041 + * @throws if the aCallback argument is not specified 1.2042 + */ 1.2043 + getAddonsByTypes: function AMI_getAddonsByTypes(aTypes, aCallback) { 1.2044 + if (!gStarted) 1.2045 + throw Components.Exception("AddonManager is not initialized", 1.2046 + Cr.NS_ERROR_NOT_INITIALIZED); 1.2047 + 1.2048 + if (aTypes && !Array.isArray(aTypes)) 1.2049 + throw Components.Exception("aTypes must be an array or null", 1.2050 + Cr.NS_ERROR_INVALID_ARG); 1.2051 + 1.2052 + if (typeof aCallback != "function") 1.2053 + throw Components.Exception("aCallback must be a function", 1.2054 + Cr.NS_ERROR_INVALID_ARG); 1.2055 + 1.2056 + let addons = []; 1.2057 + 1.2058 + new AsyncObjectCaller(this.providers, "getAddonsByTypes", { 1.2059 + nextObject: function getAddonsByTypes_nextObject(aCaller, aProvider) { 1.2060 + callProvider(aProvider, "getAddonsByTypes", null, aTypes, 1.2061 + function getAddonsByTypes_concatAddons(aProviderAddons) { 1.2062 + addons = addons.concat(aProviderAddons); 1.2063 + aCaller.callNext(); 1.2064 + }); 1.2065 + }, 1.2066 + 1.2067 + noMoreObjects: function getAddonsByTypes_noMoreObjects(aCaller) { 1.2068 + safeCall(aCallback, addons); 1.2069 + } 1.2070 + }); 1.2071 + }, 1.2072 + 1.2073 + /** 1.2074 + * Asynchronously gets all installed add-ons. 1.2075 + * 1.2076 + * @param aCallback 1.2077 + * A callback which will be passed an array of Addons 1.2078 + */ 1.2079 + getAllAddons: function AMI_getAllAddons(aCallback) { 1.2080 + if (!gStarted) 1.2081 + throw Components.Exception("AddonManager is not initialized", 1.2082 + Cr.NS_ERROR_NOT_INITIALIZED); 1.2083 + 1.2084 + if (typeof aCallback != "function") 1.2085 + throw Components.Exception("aCallback must be a function", 1.2086 + Cr.NS_ERROR_INVALID_ARG); 1.2087 + 1.2088 + this.getAddonsByTypes(null, aCallback); 1.2089 + }, 1.2090 + 1.2091 + /** 1.2092 + * Asynchronously gets add-ons that have operations waiting for an application 1.2093 + * restart to complete. 1.2094 + * 1.2095 + * @param aTypes 1.2096 + * An optional array of types to retrieve. Each type is a string name 1.2097 + * @param aCallback 1.2098 + * The callback to pass the array of Addons to 1.2099 + * @throws if the aCallback argument is not specified 1.2100 + */ 1.2101 + getAddonsWithOperationsByTypes: 1.2102 + function AMI_getAddonsWithOperationsByTypes(aTypes, aCallback) { 1.2103 + if (!gStarted) 1.2104 + throw Components.Exception("AddonManager is not initialized", 1.2105 + Cr.NS_ERROR_NOT_INITIALIZED); 1.2106 + 1.2107 + if (aTypes && !Array.isArray(aTypes)) 1.2108 + throw Components.Exception("aTypes must be an array or null", 1.2109 + Cr.NS_ERROR_INVALID_ARG); 1.2110 + 1.2111 + if (typeof aCallback != "function") 1.2112 + throw Components.Exception("aCallback must be a function", 1.2113 + Cr.NS_ERROR_INVALID_ARG); 1.2114 + 1.2115 + let addons = []; 1.2116 + 1.2117 + new AsyncObjectCaller(this.providers, "getAddonsWithOperationsByTypes", { 1.2118 + nextObject: function getAddonsWithOperationsByTypes_nextObject 1.2119 + (aCaller, aProvider) { 1.2120 + callProvider(aProvider, "getAddonsWithOperationsByTypes", null, aTypes, 1.2121 + function getAddonsWithOperationsByTypes_concatAddons 1.2122 + (aProviderAddons) { 1.2123 + addons = addons.concat(aProviderAddons); 1.2124 + aCaller.callNext(); 1.2125 + }); 1.2126 + }, 1.2127 + 1.2128 + noMoreObjects: function getAddonsWithOperationsByTypes_noMoreObjects(caller) { 1.2129 + safeCall(aCallback, addons); 1.2130 + } 1.2131 + }); 1.2132 + }, 1.2133 + 1.2134 + /** 1.2135 + * Adds a new AddonManagerListener if the listener is not already registered. 1.2136 + * 1.2137 + * @param aListener 1.2138 + * The listener to add 1.2139 + */ 1.2140 + addManagerListener: function AMI_addManagerListener(aListener) { 1.2141 + if (!aListener || typeof aListener != "object") 1.2142 + throw Components.Exception("aListener must be an AddonManagerListener object", 1.2143 + Cr.NS_ERROR_INVALID_ARG); 1.2144 + 1.2145 + if (!this.managerListeners.some(function addManagerListener_matchListener(i) { 1.2146 + return i == aListener; })) 1.2147 + this.managerListeners.push(aListener); 1.2148 + }, 1.2149 + 1.2150 + /** 1.2151 + * Removes an AddonManagerListener if the listener is registered. 1.2152 + * 1.2153 + * @param aListener 1.2154 + * The listener to remove 1.2155 + */ 1.2156 + removeManagerListener: function AMI_removeManagerListener(aListener) { 1.2157 + if (!aListener || typeof aListener != "object") 1.2158 + throw Components.Exception("aListener must be an AddonManagerListener object", 1.2159 + Cr.NS_ERROR_INVALID_ARG); 1.2160 + 1.2161 + let pos = 0; 1.2162 + while (pos < this.managerListeners.length) { 1.2163 + if (this.managerListeners[pos] == aListener) 1.2164 + this.managerListeners.splice(pos, 1); 1.2165 + else 1.2166 + pos++; 1.2167 + } 1.2168 + }, 1.2169 + 1.2170 + /** 1.2171 + * Adds a new AddonListener if the listener is not already registered. 1.2172 + * 1.2173 + * @param aListener 1.2174 + * The AddonListener to add 1.2175 + */ 1.2176 + addAddonListener: function AMI_addAddonListener(aListener) { 1.2177 + if (!aListener || typeof aListener != "object") 1.2178 + throw Components.Exception("aListener must be an AddonListener object", 1.2179 + Cr.NS_ERROR_INVALID_ARG); 1.2180 + 1.2181 + if (!this.addonListeners.some(function addAddonListener_matchListener(i) { 1.2182 + return i == aListener; })) 1.2183 + this.addonListeners.push(aListener); 1.2184 + }, 1.2185 + 1.2186 + /** 1.2187 + * Removes an AddonListener if the listener is registered. 1.2188 + * 1.2189 + * @param aListener 1.2190 + * The AddonListener to remove 1.2191 + */ 1.2192 + removeAddonListener: function AMI_removeAddonListener(aListener) { 1.2193 + if (!aListener || typeof aListener != "object") 1.2194 + throw Components.Exception("aListener must be an AddonListener object", 1.2195 + Cr.NS_ERROR_INVALID_ARG); 1.2196 + 1.2197 + let pos = 0; 1.2198 + while (pos < this.addonListeners.length) { 1.2199 + if (this.addonListeners[pos] == aListener) 1.2200 + this.addonListeners.splice(pos, 1); 1.2201 + else 1.2202 + pos++; 1.2203 + } 1.2204 + }, 1.2205 + 1.2206 + /** 1.2207 + * Adds a new TypeListener if the listener is not already registered. 1.2208 + * 1.2209 + * @param aListener 1.2210 + * The TypeListener to add 1.2211 + */ 1.2212 + addTypeListener: function AMI_addTypeListener(aListener) { 1.2213 + if (!aListener || typeof aListener != "object") 1.2214 + throw Components.Exception("aListener must be a TypeListener object", 1.2215 + Cr.NS_ERROR_INVALID_ARG); 1.2216 + 1.2217 + if (!this.typeListeners.some(function addTypeListener_matchListener(i) { 1.2218 + return i == aListener; })) 1.2219 + this.typeListeners.push(aListener); 1.2220 + }, 1.2221 + 1.2222 + /** 1.2223 + * Removes an TypeListener if the listener is registered. 1.2224 + * 1.2225 + * @param aListener 1.2226 + * The TypeListener to remove 1.2227 + */ 1.2228 + removeTypeListener: function AMI_removeTypeListener(aListener) { 1.2229 + if (!aListener || typeof aListener != "object") 1.2230 + throw Components.Exception("aListener must be a TypeListener object", 1.2231 + Cr.NS_ERROR_INVALID_ARG); 1.2232 + 1.2233 + let pos = 0; 1.2234 + while (pos < this.typeListeners.length) { 1.2235 + if (this.typeListeners[pos] == aListener) 1.2236 + this.typeListeners.splice(pos, 1); 1.2237 + else 1.2238 + pos++; 1.2239 + } 1.2240 + }, 1.2241 + 1.2242 + get addonTypes() { 1.2243 + return this.typesProxy; 1.2244 + }, 1.2245 + 1.2246 + get autoUpdateDefault() { 1.2247 + return gAutoUpdateDefault; 1.2248 + }, 1.2249 + 1.2250 + set autoUpdateDefault(aValue) { 1.2251 + aValue = !!aValue; 1.2252 + if (aValue != gAutoUpdateDefault) 1.2253 + Services.prefs.setBoolPref(PREF_EM_AUTOUPDATE_DEFAULT, aValue); 1.2254 + return aValue; 1.2255 + }, 1.2256 + 1.2257 + get checkCompatibility() { 1.2258 + return gCheckCompatibility; 1.2259 + }, 1.2260 + 1.2261 + set checkCompatibility(aValue) { 1.2262 + aValue = !!aValue; 1.2263 + if (aValue != gCheckCompatibility) { 1.2264 + if (!aValue) 1.2265 + Services.prefs.setBoolPref(PREF_EM_CHECK_COMPATIBILITY, false); 1.2266 + else 1.2267 + Services.prefs.clearUserPref(PREF_EM_CHECK_COMPATIBILITY); 1.2268 + } 1.2269 + return aValue; 1.2270 + }, 1.2271 + 1.2272 + get strictCompatibility() { 1.2273 + return gStrictCompatibility; 1.2274 + }, 1.2275 + 1.2276 + set strictCompatibility(aValue) { 1.2277 + aValue = !!aValue; 1.2278 + if (aValue != gStrictCompatibility) 1.2279 + Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, aValue); 1.2280 + return aValue; 1.2281 + }, 1.2282 + 1.2283 + get checkUpdateSecurityDefault() { 1.2284 + return gCheckUpdateSecurityDefault; 1.2285 + }, 1.2286 + 1.2287 + get checkUpdateSecurity() { 1.2288 + return gCheckUpdateSecurity; 1.2289 + }, 1.2290 + 1.2291 + set checkUpdateSecurity(aValue) { 1.2292 + aValue = !!aValue; 1.2293 + if (aValue != gCheckUpdateSecurity) { 1.2294 + if (aValue != gCheckUpdateSecurityDefault) 1.2295 + Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, aValue); 1.2296 + else 1.2297 + Services.prefs.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY); 1.2298 + } 1.2299 + return aValue; 1.2300 + }, 1.2301 + 1.2302 + get updateEnabled() { 1.2303 + return gUpdateEnabled; 1.2304 + }, 1.2305 + 1.2306 + set updateEnabled(aValue) { 1.2307 + aValue = !!aValue; 1.2308 + if (aValue != gUpdateEnabled) 1.2309 + Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue); 1.2310 + return aValue; 1.2311 + }, 1.2312 + 1.2313 + get hotfixID() { 1.2314 + return gHotfixID; 1.2315 + }, 1.2316 +}; 1.2317 + 1.2318 +/** 1.2319 + * Should not be used outside of core Mozilla code. This is a private API for 1.2320 + * the startup and platform integration code to use. Refer to the methods on 1.2321 + * AddonManagerInternal for documentation however note that these methods are 1.2322 + * subject to change at any time. 1.2323 + */ 1.2324 +this.AddonManagerPrivate = { 1.2325 + startup: function AMP_startup() { 1.2326 + AddonManagerInternal.startup(); 1.2327 + }, 1.2328 + 1.2329 + registerProvider: function AMP_registerProvider(aProvider, aTypes) { 1.2330 + AddonManagerInternal.registerProvider(aProvider, aTypes); 1.2331 + }, 1.2332 + 1.2333 + unregisterProvider: function AMP_unregisterProvider(aProvider) { 1.2334 + AddonManagerInternal.unregisterProvider(aProvider); 1.2335 + }, 1.2336 + 1.2337 + backgroundUpdateCheck: function AMP_backgroundUpdateCheck() { 1.2338 + AddonManagerInternal.backgroundUpdateCheck(); 1.2339 + }, 1.2340 + 1.2341 + addStartupChange: function AMP_addStartupChange(aType, aID) { 1.2342 + AddonManagerInternal.addStartupChange(aType, aID); 1.2343 + }, 1.2344 + 1.2345 + removeStartupChange: function AMP_removeStartupChange(aType, aID) { 1.2346 + AddonManagerInternal.removeStartupChange(aType, aID); 1.2347 + }, 1.2348 + 1.2349 + notifyAddonChanged: function AMP_notifyAddonChanged(aID, aType, aPendingRestart) { 1.2350 + AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart); 1.2351 + }, 1.2352 + 1.2353 + updateAddonAppDisabledStates: function AMP_updateAddonAppDisabledStates() { 1.2354 + AddonManagerInternal.updateAddonAppDisabledStates(); 1.2355 + }, 1.2356 + 1.2357 + updateAddonRepositoryData: function AMP_updateAddonRepositoryData(aCallback) { 1.2358 + AddonManagerInternal.updateAddonRepositoryData(aCallback); 1.2359 + }, 1.2360 + 1.2361 + callInstallListeners: function AMP_callInstallListeners(...aArgs) { 1.2362 + return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal, 1.2363 + aArgs); 1.2364 + }, 1.2365 + 1.2366 + callAddonListeners: function AMP_callAddonListeners(...aArgs) { 1.2367 + AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs); 1.2368 + }, 1.2369 + 1.2370 + AddonAuthor: AddonAuthor, 1.2371 + 1.2372 + AddonScreenshot: AddonScreenshot, 1.2373 + 1.2374 + AddonCompatibilityOverride: AddonCompatibilityOverride, 1.2375 + 1.2376 + AddonType: AddonType, 1.2377 + 1.2378 + recordTimestamp: function AMP_recordTimestamp(name, value) { 1.2379 + AddonManagerInternal.recordTimestamp(name, value); 1.2380 + }, 1.2381 + 1.2382 + _simpleMeasures: {}, 1.2383 + recordSimpleMeasure: function AMP_recordSimpleMeasure(name, value) { 1.2384 + this._simpleMeasures[name] = value; 1.2385 + }, 1.2386 + 1.2387 + recordException: function AMP_recordException(aModule, aContext, aException) { 1.2388 + let report = { 1.2389 + module: aModule, 1.2390 + context: aContext 1.2391 + }; 1.2392 + 1.2393 + if (typeof aException == "number") { 1.2394 + report.message = Components.Exception("", aException).name; 1.2395 + } 1.2396 + else { 1.2397 + report.message = aException.toString(); 1.2398 + if (aException.fileName) { 1.2399 + report.file = aException.fileName; 1.2400 + report.line = aException.lineNumber; 1.2401 + } 1.2402 + } 1.2403 + 1.2404 + this._simpleMeasures.exception = report; 1.2405 + }, 1.2406 + 1.2407 + getSimpleMeasures: function AMP_getSimpleMeasures() { 1.2408 + return this._simpleMeasures; 1.2409 + }, 1.2410 + 1.2411 + getTelemetryDetails: function AMP_getTelemetryDetails() { 1.2412 + return AddonManagerInternal.telemetryDetails; 1.2413 + }, 1.2414 + 1.2415 + setTelemetryDetails: function AMP_setTelemetryDetails(aProvider, aDetails) { 1.2416 + AddonManagerInternal.telemetryDetails[aProvider] = aDetails; 1.2417 + }, 1.2418 + 1.2419 + // Start a timer, record a simple measure of the time interval when 1.2420 + // timer.done() is called 1.2421 + simpleTimer: function(aName) { 1.2422 + let startTime = Date.now(); 1.2423 + return { 1.2424 + done: () => this.recordSimpleMeasure(aName, Date.now() - startTime) 1.2425 + }; 1.2426 + }, 1.2427 + 1.2428 + /** 1.2429 + * Helper to call update listeners when no update is available. 1.2430 + * 1.2431 + * This can be used as an implementation for Addon.findUpdates() when 1.2432 + * no update mechanism is available. 1.2433 + */ 1.2434 + callNoUpdateListeners: function (addon, listener, reason, appVersion, platformVersion) { 1.2435 + if ("onNoCompatibilityUpdateAvailable" in listener) { 1.2436 + safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon); 1.2437 + } 1.2438 + if ("onNoUpdateAvailable" in listener) { 1.2439 + safeCall(listener.onNoUpdateAvailable.bind(listener), addon); 1.2440 + } 1.2441 + if ("onUpdateFinished" in listener) { 1.2442 + safeCall(listener.onUpdateFinished.bind(listener), addon); 1.2443 + } 1.2444 + }, 1.2445 +}; 1.2446 + 1.2447 +/** 1.2448 + * This is the public API that UI and developers should be calling. All methods 1.2449 + * just forward to AddonManagerInternal. 1.2450 + */ 1.2451 +this.AddonManager = { 1.2452 + // Constants for the AddonInstall.state property 1.2453 + // The install is available for download. 1.2454 + STATE_AVAILABLE: 0, 1.2455 + // The install is being downloaded. 1.2456 + STATE_DOWNLOADING: 1, 1.2457 + // The install is checking for compatibility information. 1.2458 + STATE_CHECKING: 2, 1.2459 + // The install is downloaded and ready to install. 1.2460 + STATE_DOWNLOADED: 3, 1.2461 + // The download failed. 1.2462 + STATE_DOWNLOAD_FAILED: 4, 1.2463 + // The add-on is being installed. 1.2464 + STATE_INSTALLING: 5, 1.2465 + // The add-on has been installed. 1.2466 + STATE_INSTALLED: 6, 1.2467 + // The install failed. 1.2468 + STATE_INSTALL_FAILED: 7, 1.2469 + // The install has been cancelled. 1.2470 + STATE_CANCELLED: 8, 1.2471 + 1.2472 + // Constants representing different types of errors while downloading an 1.2473 + // add-on. 1.2474 + // The download failed due to network problems. 1.2475 + ERROR_NETWORK_FAILURE: -1, 1.2476 + // The downloaded file did not match the provided hash. 1.2477 + ERROR_INCORRECT_HASH: -2, 1.2478 + // The downloaded file seems to be corrupted in some way. 1.2479 + ERROR_CORRUPT_FILE: -3, 1.2480 + // An error occured trying to write to the filesystem. 1.2481 + ERROR_FILE_ACCESS: -4, 1.2482 + 1.2483 + // These must be kept in sync with AddonUpdateChecker. 1.2484 + // No error was encountered. 1.2485 + UPDATE_STATUS_NO_ERROR: 0, 1.2486 + // The update check timed out 1.2487 + UPDATE_STATUS_TIMEOUT: -1, 1.2488 + // There was an error while downloading the update information. 1.2489 + UPDATE_STATUS_DOWNLOAD_ERROR: -2, 1.2490 + // The update information was malformed in some way. 1.2491 + UPDATE_STATUS_PARSE_ERROR: -3, 1.2492 + // The update information was not in any known format. 1.2493 + UPDATE_STATUS_UNKNOWN_FORMAT: -4, 1.2494 + // The update information was not correctly signed or there was an SSL error. 1.2495 + UPDATE_STATUS_SECURITY_ERROR: -5, 1.2496 + // The update was cancelled. 1.2497 + UPDATE_STATUS_CANCELLED: -6, 1.2498 + 1.2499 + // Constants to indicate why an update check is being performed 1.2500 + // Update check has been requested by the user. 1.2501 + UPDATE_WHEN_USER_REQUESTED: 1, 1.2502 + // Update check is necessary to see if the Addon is compatibile with a new 1.2503 + // version of the application. 1.2504 + UPDATE_WHEN_NEW_APP_DETECTED: 2, 1.2505 + // Update check is necessary because a new application has been installed. 1.2506 + UPDATE_WHEN_NEW_APP_INSTALLED: 3, 1.2507 + // Update check is a regular background update check. 1.2508 + UPDATE_WHEN_PERIODIC_UPDATE: 16, 1.2509 + // Update check is needed to check an Addon that is being installed. 1.2510 + UPDATE_WHEN_ADDON_INSTALLED: 17, 1.2511 + 1.2512 + // Constants for operations in Addon.pendingOperations 1.2513 + // Indicates that the Addon has no pending operations. 1.2514 + PENDING_NONE: 0, 1.2515 + // Indicates that the Addon will be enabled after the application restarts. 1.2516 + PENDING_ENABLE: 1, 1.2517 + // Indicates that the Addon will be disabled after the application restarts. 1.2518 + PENDING_DISABLE: 2, 1.2519 + // Indicates that the Addon will be uninstalled after the application restarts. 1.2520 + PENDING_UNINSTALL: 4, 1.2521 + // Indicates that the Addon will be installed after the application restarts. 1.2522 + PENDING_INSTALL: 8, 1.2523 + PENDING_UPGRADE: 16, 1.2524 + 1.2525 + // Constants for operations in Addon.operationsRequiringRestart 1.2526 + // Indicates that restart isn't required for any operation. 1.2527 + OP_NEEDS_RESTART_NONE: 0, 1.2528 + // Indicates that restart is required for enabling the addon. 1.2529 + OP_NEEDS_RESTART_ENABLE: 1, 1.2530 + // Indicates that restart is required for disabling the addon. 1.2531 + OP_NEEDS_RESTART_DISABLE: 2, 1.2532 + // Indicates that restart is required for uninstalling the addon. 1.2533 + OP_NEEDS_RESTART_UNINSTALL: 4, 1.2534 + // Indicates that restart is required for installing the addon. 1.2535 + OP_NEEDS_RESTART_INSTALL: 8, 1.2536 + 1.2537 + // Constants for permissions in Addon.permissions. 1.2538 + // Indicates that the Addon can be uninstalled. 1.2539 + PERM_CAN_UNINSTALL: 1, 1.2540 + // Indicates that the Addon can be enabled by the user. 1.2541 + PERM_CAN_ENABLE: 2, 1.2542 + // Indicates that the Addon can be disabled by the user. 1.2543 + PERM_CAN_DISABLE: 4, 1.2544 + // Indicates that the Addon can be upgraded. 1.2545 + PERM_CAN_UPGRADE: 8, 1.2546 + // Indicates that the Addon can be set to be optionally enabled 1.2547 + // on a case-by-case basis. 1.2548 + PERM_CAN_ASK_TO_ACTIVATE: 16, 1.2549 + 1.2550 + // General descriptions of where items are installed. 1.2551 + // Installed in this profile. 1.2552 + SCOPE_PROFILE: 1, 1.2553 + // Installed for all of this user's profiles. 1.2554 + SCOPE_USER: 2, 1.2555 + // Installed and owned by the application. 1.2556 + SCOPE_APPLICATION: 4, 1.2557 + // Installed for all users of the computer. 1.2558 + SCOPE_SYSTEM: 8, 1.2559 + // The combination of all scopes. 1.2560 + SCOPE_ALL: 15, 1.2561 + 1.2562 + // 1-15 are different built-in views for the add-on type 1.2563 + VIEW_TYPE_LIST: "list", 1.2564 + 1.2565 + TYPE_UI_HIDE_EMPTY: 16, 1.2566 + // Indicates that this add-on type supports the ask-to-activate state. 1.2567 + // That is, add-ons of this type can be set to be optionally enabled 1.2568 + // on a case-by-case basis. 1.2569 + TYPE_SUPPORTS_ASK_TO_ACTIVATE: 32, 1.2570 + 1.2571 + // Constants for Addon.applyBackgroundUpdates. 1.2572 + // Indicates that the Addon should not update automatically. 1.2573 + AUTOUPDATE_DISABLE: 0, 1.2574 + // Indicates that the Addon should update automatically only if 1.2575 + // that's the global default. 1.2576 + AUTOUPDATE_DEFAULT: 1, 1.2577 + // Indicates that the Addon should update automatically. 1.2578 + AUTOUPDATE_ENABLE: 2, 1.2579 + 1.2580 + // Constants for how Addon options should be shown. 1.2581 + // Options will be opened in a new window 1.2582 + OPTIONS_TYPE_DIALOG: 1, 1.2583 + // Options will be displayed within the AM detail view 1.2584 + OPTIONS_TYPE_INLINE: 2, 1.2585 + // Options will be displayed in a new tab, if possible 1.2586 + OPTIONS_TYPE_TAB: 3, 1.2587 + // Same as OPTIONS_TYPE_INLINE, but no Preferences button will be shown. 1.2588 + // Used to indicate that only non-interactive information will be shown. 1.2589 + OPTIONS_TYPE_INLINE_INFO: 4, 1.2590 + 1.2591 + // Constants for displayed or hidden options notifications 1.2592 + // Options notification will be displayed 1.2593 + OPTIONS_NOTIFICATION_DISPLAYED: "addon-options-displayed", 1.2594 + // Options notification will be hidden 1.2595 + OPTIONS_NOTIFICATION_HIDDEN: "addon-options-hidden", 1.2596 + 1.2597 + // Constants for getStartupChanges, addStartupChange and removeStartupChange 1.2598 + // Add-ons that were detected as installed during startup. Doesn't include 1.2599 + // add-ons that were pending installation the last time the application ran. 1.2600 + STARTUP_CHANGE_INSTALLED: "installed", 1.2601 + // Add-ons that were detected as changed during startup. This includes an 1.2602 + // add-on moving to a different location, changing version or just having 1.2603 + // been detected as possibly changed. 1.2604 + STARTUP_CHANGE_CHANGED: "changed", 1.2605 + // Add-ons that were detected as uninstalled during startup. Doesn't include 1.2606 + // add-ons that were pending uninstallation the last time the application ran. 1.2607 + STARTUP_CHANGE_UNINSTALLED: "uninstalled", 1.2608 + // Add-ons that were detected as disabled during startup, normally because of 1.2609 + // an application change making an add-on incompatible. Doesn't include 1.2610 + // add-ons that were pending being disabled the last time the application ran. 1.2611 + STARTUP_CHANGE_DISABLED: "disabled", 1.2612 + // Add-ons that were detected as enabled during startup, normally because of 1.2613 + // an application change making an add-on compatible. Doesn't include 1.2614 + // add-ons that were pending being enabled the last time the application ran. 1.2615 + STARTUP_CHANGE_ENABLED: "enabled", 1.2616 + 1.2617 + // Constants for the Addon.userDisabled property 1.2618 + // Indicates that the userDisabled state of this add-on is currently 1.2619 + // ask-to-activate. That is, it can be conditionally enabled on a 1.2620 + // case-by-case basis. 1.2621 + STATE_ASK_TO_ACTIVATE: "askToActivate", 1.2622 + 1.2623 +#ifdef MOZ_EM_DEBUG 1.2624 + get __AddonManagerInternal__() { 1.2625 + return AddonManagerInternal; 1.2626 + }, 1.2627 +#endif 1.2628 + 1.2629 + getInstallForURL: function AM_getInstallForURL(aUrl, aCallback, aMimetype, 1.2630 + aHash, aName, aIcons, 1.2631 + aVersion, aLoadGroup) { 1.2632 + AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash, 1.2633 + aName, aIcons, aVersion, aLoadGroup); 1.2634 + }, 1.2635 + 1.2636 + getInstallForFile: function AM_getInstallForFile(aFile, aCallback, aMimetype) { 1.2637 + AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype); 1.2638 + }, 1.2639 + 1.2640 + /** 1.2641 + * Gets an array of add-on IDs that changed during the most recent startup. 1.2642 + * 1.2643 + * @param aType 1.2644 + * The type of startup change to get 1.2645 + * @return An array of add-on IDs 1.2646 + */ 1.2647 + getStartupChanges: function AM_getStartupChanges(aType) { 1.2648 + if (!(aType in AddonManagerInternal.startupChanges)) 1.2649 + return []; 1.2650 + return AddonManagerInternal.startupChanges[aType].slice(0); 1.2651 + }, 1.2652 + 1.2653 + getAddonByID: function AM_getAddonByID(aID, aCallback) { 1.2654 + AddonManagerInternal.getAddonByID(aID, aCallback); 1.2655 + }, 1.2656 + 1.2657 + getAddonBySyncGUID: function AM_getAddonBySyncGUID(aGUID, aCallback) { 1.2658 + AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback); 1.2659 + }, 1.2660 + 1.2661 + getAddonsByIDs: function AM_getAddonsByIDs(aIDs, aCallback) { 1.2662 + AddonManagerInternal.getAddonsByIDs(aIDs, aCallback); 1.2663 + }, 1.2664 + 1.2665 + getAddonsWithOperationsByTypes: 1.2666 + function AM_getAddonsWithOperationsByTypes(aTypes, aCallback) { 1.2667 + AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes, aCallback); 1.2668 + }, 1.2669 + 1.2670 + getAddonsByTypes: function AM_getAddonsByTypes(aTypes, aCallback) { 1.2671 + AddonManagerInternal.getAddonsByTypes(aTypes, aCallback); 1.2672 + }, 1.2673 + 1.2674 + getAllAddons: function AM_getAllAddons(aCallback) { 1.2675 + AddonManagerInternal.getAllAddons(aCallback); 1.2676 + }, 1.2677 + 1.2678 + getInstallsByTypes: function AM_getInstallsByTypes(aTypes, aCallback) { 1.2679 + AddonManagerInternal.getInstallsByTypes(aTypes, aCallback); 1.2680 + }, 1.2681 + 1.2682 + getAllInstalls: function AM_getAllInstalls(aCallback) { 1.2683 + AddonManagerInternal.getAllInstalls(aCallback); 1.2684 + }, 1.2685 + 1.2686 + mapURIToAddonID: function AM_mapURIToAddonID(aURI) { 1.2687 + return AddonManagerInternal.mapURIToAddonID(aURI); 1.2688 + }, 1.2689 + 1.2690 + isInstallEnabled: function AM_isInstallEnabled(aType) { 1.2691 + return AddonManagerInternal.isInstallEnabled(aType); 1.2692 + }, 1.2693 + 1.2694 + isInstallAllowed: function AM_isInstallAllowed(aType, aUri) { 1.2695 + return AddonManagerInternal.isInstallAllowed(aType, aUri); 1.2696 + }, 1.2697 + 1.2698 + installAddonsFromWebpage: function AM_installAddonsFromWebpage(aType, aSource, 1.2699 + aUri, aInstalls) { 1.2700 + AddonManagerInternal.installAddonsFromWebpage(aType, aSource, aUri, aInstalls); 1.2701 + }, 1.2702 + 1.2703 + addManagerListener: function AM_addManagerListener(aListener) { 1.2704 + AddonManagerInternal.addManagerListener(aListener); 1.2705 + }, 1.2706 + 1.2707 + removeManagerListener: function AM_removeManagerListener(aListener) { 1.2708 + AddonManagerInternal.removeManagerListener(aListener); 1.2709 + }, 1.2710 + 1.2711 + addInstallListener: function AM_addInstallListener(aListener) { 1.2712 + AddonManagerInternal.addInstallListener(aListener); 1.2713 + }, 1.2714 + 1.2715 + removeInstallListener: function AM_removeInstallListener(aListener) { 1.2716 + AddonManagerInternal.removeInstallListener(aListener); 1.2717 + }, 1.2718 + 1.2719 + addAddonListener: function AM_addAddonListener(aListener) { 1.2720 + AddonManagerInternal.addAddonListener(aListener); 1.2721 + }, 1.2722 + 1.2723 + removeAddonListener: function AM_removeAddonListener(aListener) { 1.2724 + AddonManagerInternal.removeAddonListener(aListener); 1.2725 + }, 1.2726 + 1.2727 + addTypeListener: function AM_addTypeListener(aListener) { 1.2728 + AddonManagerInternal.addTypeListener(aListener); 1.2729 + }, 1.2730 + 1.2731 + removeTypeListener: function AM_removeTypeListener(aListener) { 1.2732 + AddonManagerInternal.removeTypeListener(aListener); 1.2733 + }, 1.2734 + 1.2735 + get addonTypes() { 1.2736 + return AddonManagerInternal.addonTypes; 1.2737 + }, 1.2738 + 1.2739 + /** 1.2740 + * Determines whether an Addon should auto-update or not. 1.2741 + * 1.2742 + * @param aAddon 1.2743 + * The Addon representing the add-on 1.2744 + * @return true if the addon should auto-update, false otherwise. 1.2745 + */ 1.2746 + shouldAutoUpdate: function AM_shouldAutoUpdate(aAddon) { 1.2747 + if (!aAddon || typeof aAddon != "object") 1.2748 + throw Components.Exception("aAddon must be specified", 1.2749 + Cr.NS_ERROR_INVALID_ARG); 1.2750 + 1.2751 + if (!("applyBackgroundUpdates" in aAddon)) 1.2752 + return false; 1.2753 + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE) 1.2754 + return true; 1.2755 + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE) 1.2756 + return false; 1.2757 + return this.autoUpdateDefault; 1.2758 + }, 1.2759 + 1.2760 + get checkCompatibility() { 1.2761 + return AddonManagerInternal.checkCompatibility; 1.2762 + }, 1.2763 + 1.2764 + set checkCompatibility(aValue) { 1.2765 + AddonManagerInternal.checkCompatibility = aValue; 1.2766 + }, 1.2767 + 1.2768 + get strictCompatibility() { 1.2769 + return AddonManagerInternal.strictCompatibility; 1.2770 + }, 1.2771 + 1.2772 + set strictCompatibility(aValue) { 1.2773 + AddonManagerInternal.strictCompatibility = aValue; 1.2774 + }, 1.2775 + 1.2776 + get checkUpdateSecurityDefault() { 1.2777 + return AddonManagerInternal.checkUpdateSecurityDefault; 1.2778 + }, 1.2779 + 1.2780 + get checkUpdateSecurity() { 1.2781 + return AddonManagerInternal.checkUpdateSecurity; 1.2782 + }, 1.2783 + 1.2784 + set checkUpdateSecurity(aValue) { 1.2785 + AddonManagerInternal.checkUpdateSecurity = aValue; 1.2786 + }, 1.2787 + 1.2788 + get updateEnabled() { 1.2789 + return AddonManagerInternal.updateEnabled; 1.2790 + }, 1.2791 + 1.2792 + set updateEnabled(aValue) { 1.2793 + AddonManagerInternal.updateEnabled = aValue; 1.2794 + }, 1.2795 + 1.2796 + get autoUpdateDefault() { 1.2797 + return AddonManagerInternal.autoUpdateDefault; 1.2798 + }, 1.2799 + 1.2800 + set autoUpdateDefault(aValue) { 1.2801 + AddonManagerInternal.autoUpdateDefault = aValue; 1.2802 + }, 1.2803 + 1.2804 + get hotfixID() { 1.2805 + return AddonManagerInternal.hotfixID; 1.2806 + }, 1.2807 + 1.2808 + escapeAddonURI: function AM_escapeAddonURI(aAddon, aUri, aAppVersion) { 1.2809 + return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion); 1.2810 + } 1.2811 +}; 1.2812 + 1.2813 +// load the timestamps module into AddonManagerInternal 1.2814 +Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", AddonManagerInternal); 1.2815 +Object.freeze(AddonManagerInternal); 1.2816 +Object.freeze(AddonManagerPrivate); 1.2817 +Object.freeze(AddonManager);