Files
tubestation/toolkit/mozapps/extensions/addonManager.js
Kris Maglione 39c12beb57 Bug 1445551: Part 5 - Remove add-on path service. r=aswan,mccr8
The path service was created to allow us to track resources that were part of
legacy add-ons, and to map URIs ponting to those resources to add-on IDs, so
that we could apply special behavior to them.

We have better ways to track resources belonging to WebExtensions, so this
code does not benefit them in any significant way.

The only remaining legacy extensions are system add-ons, which we control, and
do not need the path service in order to track.

MozReview-Commit-ID: BKXkcaM7jJx
2018-03-13 20:21:22 -07:00

262 lines
8.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This component serves as integration between the platform and AddonManager.
* It is responsible for initializing and shutting down the AddonManager as well
* as passing new installs from webpages to the AddonManager.
*/
"use strict";
// The old XPInstall error codes
const EXECUTION_ERROR = -203;
const CANT_READ_ARCHIVE = -207;
const USER_CANCELLED = -210;
const DOWNLOAD_ERROR = -228;
const UNSUPPORTED_TYPE = -244;
const SUCCESS = 0;
const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled";
const MSG_INSTALL_ADDON = "WebInstallerInstallAddonFromWebpage";
const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback";
const MSG_PROMISE_REQUEST = "WebAPIPromiseRequest";
const MSG_PROMISE_RESULT = "WebAPIPromiseResult";
const MSG_INSTALL_EVENT = "WebAPIInstallEvent";
const MSG_INSTALL_CLEANUP = "WebAPICleanup";
const MSG_ADDON_EVENT_REQ = "WebAPIAddonEventRequest";
const MSG_ADDON_EVENT = "WebAPIAddonEvent";
const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
var gSingleton = null;
function amManager() {
ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
/* globals AddonManagerPrivate*/
Services.mm.loadFrameScript(CHILD_SCRIPT, true);
Services.mm.addMessageListener(MSG_INSTALL_ENABLED, this);
Services.mm.addMessageListener(MSG_INSTALL_ADDON, this);
Services.mm.addMessageListener(MSG_PROMISE_REQUEST, this);
Services.mm.addMessageListener(MSG_INSTALL_CLEANUP, this);
Services.mm.addMessageListener(MSG_ADDON_EVENT_REQ, this);
Services.obs.addObserver(this, "message-manager-close");
Services.obs.addObserver(this, "message-manager-disconnect");
AddonManager.webAPI.setEventHandler(this.sendEvent);
// Needed so receiveMessage can be called directly by JS callers
this.wrappedJSObject = this;
}
amManager.prototype = {
observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "addons-startup":
AddonManagerPrivate.startup();
break;
case "message-manager-close":
case "message-manager-disconnect":
this.childClosed(aSubject);
break;
}
},
installAddonFromWebpage(aMimetype, aBrowser, aInstallingPrincipal,
aUri, aHash, aName, aIcon, aCallback) {
let retval = true;
if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) {
aCallback = null;
retval = false;
}
AddonManager.getInstallForURL(aUri, function(aInstall) {
function callCallback(uri, status) {
try {
aCallback.onInstallEnded(uri, status);
} catch (e) {
Cu.reportError(e);
}
}
if (!aInstall) {
aCallback.onInstallEnded(aUri, UNSUPPORTED_TYPE);
return;
}
if (aCallback) {
aInstall.addListener({
onDownloadCancelled(aInstall) {
callCallback(aUri, USER_CANCELLED);
},
onDownloadFailed(aInstall) {
if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE)
callCallback(aUri, CANT_READ_ARCHIVE);
else
callCallback(aUri, DOWNLOAD_ERROR);
},
onInstallFailed(aInstall) {
callCallback(aUri, EXECUTION_ERROR);
},
onInstallEnded(aInstall, aStatus) {
callCallback(aUri, SUCCESS);
}
});
}
AddonManager.installAddonFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, aInstall);
}, aMimetype, aHash, aName, aIcon, null, aBrowser);
return retval;
},
notify(aTimer) {
AddonManagerPrivate.backgroundUpdateTimerHandler();
},
// Maps message manager instances for content processes to the associated
// AddonListener instances.
addonListeners: new Map(),
_addAddonListener(target) {
if (!this.addonListeners.has(target)) {
let handler = (event, id, needsRestart) => {
target.sendAsyncMessage(MSG_ADDON_EVENT, {event, id, needsRestart});
};
let listener = {
onEnabling: (addon, needsRestart) => handler("onEnabling", addon.id, needsRestart),
onEnabled: (addon) => handler("onEnabled", addon.id, false),
onDisabling: (addon, needsRestart) => handler("onDisabling", addon.id, needsRestart),
onDisabled: (addon) => handler("onDisabled", addon.id, false),
onInstalling: (addon, needsRestart) => handler("onInstalling", addon.id, needsRestart),
onInstalled: (addon) => handler("onInstalled", addon.id, false),
onUninstalling: (addon, needsRestart) => handler("onUninstalling", addon.id, needsRestart),
onUninstalled: (addon) => handler("onUninstalled", addon.id, false),
onOperationCancelled: (addon) => handler("onOperationCancelled", addon.id, false),
};
this.addonListeners.set(target, listener);
AddonManager.addAddonListener(listener);
}
},
_removeAddonListener(target) {
if (this.addonListeners.has(target)) {
AddonManager.removeAddonListener(this.addonListeners.get(target));
this.addonListeners.delete(target);
}
},
/**
* messageManager callback function.
*
* Listens to requests from child processes for InstallTrigger
* activity, and sends back callbacks.
*/
receiveMessage(aMessage) {
let payload = aMessage.data;
switch (aMessage.name) {
case MSG_INSTALL_ENABLED:
return AddonManager.isInstallEnabled(payload.mimetype);
case MSG_INSTALL_ADDON: {
let callback = null;
if (payload.callbackID != -1) {
let mm = aMessage.target.messageManager;
callback = {
onInstallEnded(url, status) {
mm.sendAsyncMessage(MSG_INSTALL_CALLBACK, {
callbackID: payload.callbackID,
url,
status
});
},
};
}
return this.installAddonFromWebpage(payload.mimetype,
aMessage.target, payload.triggeringPrincipal, payload.uri,
payload.hash, payload.name, payload.icon, callback);
}
case MSG_PROMISE_REQUEST: {
let mm = aMessage.target.messageManager;
let resolve = (value) => {
mm.sendAsyncMessage(MSG_PROMISE_RESULT, {
callbackID: payload.callbackID,
resolve: value
});
};
let reject = (value) => {
mm.sendAsyncMessage(MSG_PROMISE_RESULT, {
callbackID: payload.callbackID,
reject: value
});
};
let API = AddonManager.webAPI;
if (payload.type in API) {
API[payload.type](aMessage.target, ...payload.args).then(resolve, reject);
} else {
reject("Unknown Add-on API request.");
}
break;
}
case MSG_INSTALL_CLEANUP: {
AddonManager.webAPI.clearInstalls(payload.ids);
break;
}
case MSG_ADDON_EVENT_REQ: {
let target = aMessage.target.messageManager;
if (payload.enabled) {
this._addAddonListener(target);
} else {
this._removeAddonListener(target);
}
}
}
return undefined;
},
childClosed(target) {
AddonManager.webAPI.clearInstallsFrom(target);
this._removeAddonListener(target);
},
sendEvent(mm, data) {
mm.sendAsyncMessage(MSG_INSTALL_EVENT, data);
},
classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"),
_xpcom_factory: {
createInstance(aOuter, aIid) {
if (aOuter != null)
throw Components.Exception("Component does not support aggregation",
Cr.NS_ERROR_NO_AGGREGATION);
if (!gSingleton)
gSingleton = new amManager();
return gSingleton.QueryInterface(aIid);
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.amIAddonManager,
Ci.nsITimerCallback,
Ci.nsIObserver,
Ci.nsIMessageListener])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amManager]);