summaryrefslogtreecommitdiffstats
path: root/dom/system/SystemUpdateService.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/SystemUpdateService.jsm')
-rw-r--r--dom/system/SystemUpdateService.jsm382
1 files changed, 382 insertions, 0 deletions
diff --git a/dom/system/SystemUpdateService.jsm b/dom/system/SystemUpdateService.jsm
new file mode 100644
index 000000000..41647ea8f
--- /dev/null
+++ b/dom/system/SystemUpdateService.jsm
@@ -0,0 +1,382 @@
+/* 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/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+this.EXPORTED_SYMBOLS = ["SystemUpdateService"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const CATEGORY_SYSTEM_UPDATE_PROVIDER = "system-update-provider";
+const PROVIDER_ACTIVITY_IDLE = 0;
+const PROVIDER_ACTIVITY_CHECKING = 1;
+const PROVIDER_ACTIVITY_DOWNLOADING = 1 << 1;
+const PROVIDER_ACTIVITY_APPLYING = 1 << 2;
+
+var debug = Services.prefs.getBoolPref("dom.system_update.debug")
+ ? (aMsg) => dump("-*- SystemUpdateService.jsm : " + aMsg + "\n")
+ : (aMsg) => {};
+
+XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
+ "@mozilla.org/parentprocessmessagemanager;1",
+ "nsIMessageBroadcaster");
+
+function ActiveProvider(aProvider) {
+ this.id = aProvider.id;
+ this._instance = Components.classesByID[aProvider.id].getService(Ci.nsISystemUpdateProvider);
+ this._instance.setListener(this);
+}
+
+ActiveProvider.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemUpdateListener]),
+
+ _activity: PROVIDER_ACTIVITY_IDLE,
+
+ destroy: function() {
+ if (this._instance) {
+ this._instance.unsetListener();
+ this._instance = null;
+ }
+
+ this.id = null;
+ },
+
+ checkForUpdate: function() {
+ this._execFuncIfNotInActivity(PROVIDER_ACTIVITY_CHECKING,
+ this._instance.checkForUpdate);
+ },
+
+ startDownload: function() {
+ this._execFuncIfNotInActivity(PROVIDER_ACTIVITY_DOWNLOADING,
+ this._instance.startDownload);
+ },
+
+ stopDownload: function() {
+ this._execFuncIfNotInActivity(PROVIDER_ACTIVITY_DOWNLOADING,
+ this._instance.stopDownload);
+ },
+
+ applyUpdate: function() {
+ this._execFuncIfNotInActivity(PROVIDER_ACTIVITY_APPLYING,
+ this._instance.applyUpdate);
+ },
+
+ setParameter: function(aName, aValue) {
+ return this._instance.setParameter(aName, aValue);
+ },
+
+ getParameter: function(aName) {
+ return this._instance.getParameter(aName);
+ },
+
+ // nsISystemUpdateListener
+ onUpdateAvailable: function(aType, aVersion, aDescription, aBuildDate, aSize) {
+ this._execFuncIfActiveAndInAction(PROVIDER_ACTIVITY_CHECKING, function() {
+ ppmm.broadcastAsyncMessage("SystemUpdate:OnUpdateAvailable", {
+ uuid: this.id,
+ packageInfo: {
+ type: aType,
+ version: aVersion,
+ description: aDescription,
+ buildDate: aBuildDate,
+ size: aSize,
+ }
+ });
+
+ this._unsetActivity(PROVIDER_ACTIVITY_CHECKING);
+ }.bind(this));
+ },
+
+ onProgress: function(aLoaded, aTotal) {
+ this._execFuncIfActiveAndInAction(PROVIDER_ACTIVITY_DOWNLOADING, function() {
+ ppmm.broadcastAsyncMessage("SystemUpdate:OnProgress", {
+ uuid: this.id,
+ loaded: aLoaded,
+ total: aTotal,
+ });
+ }.bind(this));
+ },
+
+ onUpdateReady: function() {
+ this._execFuncIfActiveAndInAction(PROVIDER_ACTIVITY_DOWNLOADING, function() {
+ ppmm.broadcastAsyncMessage("SystemUpdate:OnUpdateReady", {
+ uuid: this.id,
+ });
+
+ this._unsetActivity(PROVIDER_ACTIVITY_DOWNLOADING);
+ }.bind(this));
+ },
+
+ onError: function(aErrMsg) {
+ if (!SystemUpdateService._isActiveProviderId(this.id)) {
+ return;
+ }
+
+ ppmm.broadcastAsyncMessage("SystemUpdate:OnError", {
+ uuid: this.id,
+ message: aErrMsg,
+ });
+
+ this._activity = PROVIDER_ACTIVITY_IDLE;
+ },
+
+ isIdle: function() {
+ return this._activity === PROVIDER_ACTIVITY_IDLE;
+ },
+
+ _isInActivity: function(aActivity) {
+ return (this._activity & aActivity) !== PROVIDER_ACTIVITY_IDLE;
+ },
+
+ _setActivity: function(aActivity) {
+ this._activity |= aActivity;
+ },
+
+ _unsetActivity: function(aActivity) {
+ this._activity &= ~aActivity;
+ },
+
+ _execFuncIfNotInActivity: function(aActivity, aFunc) {
+ if (!this._isInActivity(aActivity)) {
+ this._setActivity(aActivity);
+ aFunc();
+ }
+ },
+
+ _execFuncIfActiveAndInAction: function(aActivity, aFunc) {
+ if (!SystemUpdateService._isActiveProviderId(this.id)) {
+ return;
+ }
+ if (this._isInActivity(aActivity)) {
+ aFunc();
+ }
+ },
+
+};
+
+this.SystemUpdateService = {
+ _providers: [],
+ _activeProvider: null,
+
+ _updateActiveProvider: function(aProvider) {
+ if (this._activeProvider) {
+ this._activeProvider.destroy();
+ }
+
+ this._activeProvider = new ActiveProvider(aProvider);
+ },
+
+ _isActiveProviderId: function(aId) {
+ return (this._activeProvider && this._activeProvider.id === aId);
+ },
+
+ init: function() {
+ debug("init");
+
+ let messages = ["SystemUpdate:GetProviders",
+ "SystemUpdate:GetActiveProvider",
+ "SystemUpdate:SetActiveProvider",
+ "SystemUpdate:CheckForUpdate",
+ "SystemUpdate:StartDownload",
+ "SystemUpdate:StopDownload",
+ "SystemUpdate:ApplyUpdate",
+ "SystemUpdate:SetParameter",
+ "SystemUpdate:GetParameter"];
+ messages.forEach((function(aMsgName) {
+ ppmm.addMessageListener(aMsgName, this);
+ }).bind(this));
+
+ // load available provider list
+ let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+ let entries = catMan.enumerateCategory(CATEGORY_SYSTEM_UPDATE_PROVIDER);
+ while (entries.hasMoreElements()) {
+ let name = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
+ let [contractId, id] = catMan.getCategoryEntry(CATEGORY_SYSTEM_UPDATE_PROVIDER, name).split(",");
+ this._providers.push({
+ id: id,
+ name: name,
+ contractId: contractId
+ });
+ }
+ debug("available providers: " + JSON.stringify(this._providers));
+
+ // setup default active provider
+ let defaultActive;
+ try {
+ defaultActive = Services.prefs.getCharPref("dom.system_update.active");
+ } catch (e) {}
+
+ if (defaultActive) {
+ let defaultProvider = this._providers.find(function(aProvider) {
+ return aProvider.contractId === defaultActive;
+ });
+
+ if (defaultProvider) {
+ this._updateActiveProvider(defaultProvider);
+ }
+ }
+ },
+
+ addProvider: function(aClassId, aContractId, aName) {
+ debug("addProvider");
+
+ //did not allow null or empty string to add.
+ if(!aClassId || !aContractId || !aName) {
+ return;
+ }
+
+ let existedProvider = this._providers.find(function(provider) {
+ return provider.id === aClassId;
+ });
+
+ //skip if adding the existed provider.
+ if (existedProvider) {
+ debug("existing providers: " + JSON.stringify(existedProvider));
+ return;
+ }
+
+ //dynamically add the provider info to list.
+ this._providers.push({
+ id: aClassId,
+ name: aName,
+ contractId: aContractId
+ });
+ debug("available providers: " + JSON.stringify(this._providers));
+ },
+
+ getProviders: function(aData, aMm) {
+ debug("getProviders");
+
+ aData.providers = [];
+ for (let provider of this._providers) {
+ aData.providers.push({
+ name: provider.name,
+ uuid: provider.id
+ });
+ }
+ aMm.sendAsyncMessage("SystemUpdate:GetProviders:Result:OK", aData);
+ },
+
+ getActiveProvider: function(aData, aMm) {
+ debug("getActiveProvider");
+
+ let self = this;
+ let providerInfo = this._providers.find(function(provider) {
+ return self._isActiveProviderId(provider.id);
+ });
+
+ if (!providerInfo) {
+ aData.error = "NotFoundError";
+ aMm.sendAsyncMessage("SystemUpdate:GetActiveProvider:Result:Error", aData);
+ return;
+ }
+
+ aData.provider = {
+ name: providerInfo.name,
+ uuid: providerInfo.id
+ };
+ aMm.sendAsyncMessage("SystemUpdate:GetActiveProvider:Result:OK", aData);
+ },
+
+ setActiveProvider: function(aData, aMm) {
+ debug("setActiveProvider");
+
+ let self = this;
+ let selectedProvider = this._providers.find(function(provider) {
+ return provider.id === aData.uuid;
+ });
+
+ if (!selectedProvider) {
+ aData.error = "DataError";
+ aMm.sendAsyncMessage("SystemUpdate:SetActiveProvider:Result:Error", aData);
+ return;
+ }
+
+ if (!this._isActiveProviderId(selectedProvider.id)) {
+ // not allow changing active provider while there is an ongoing update activity
+ if (this.activeProvider && !this._activeProvider.isIdle()) {
+ aData.error = "DataError";
+ aMm.sendAsyncMessage("SystemUpdate:SetActiveProvider:Result:Error", aData);
+ return;
+ }
+
+ this._updateActiveProvider(selectedProvider);
+ Services.prefs.setCharPref("dom.system_update.active", selectedProvider.contractId);
+ }
+
+ aData.provider = {
+ name: selectedProvider.name,
+ uuid: selectedProvider.id
+ };
+ aMm.sendAsyncMessage("SystemUpdate:SetActiveProvider:Result:OK", aData);
+ },
+
+ receiveMessage: function(aMessage) {
+ if (!aMessage.target.assertPermission("system-update")) {
+ debug("receive message " + aMessage.name +
+ " from a content process with no 'system-update' privileges.");
+ return null;
+ }
+
+ let msg = aMessage.data || {};
+ let mm = aMessage.target;
+
+ switch (aMessage.name) {
+ case "SystemUpdate:GetProviders": {
+ this.getProviders(msg, mm);
+ break;
+ }
+ case "SystemUpdate:GetActiveProvider": {
+ this.getActiveProvider(msg, mm);
+ break;
+ }
+ case "SystemUpdate:SetActiveProvider": {
+ this.setActiveProvider(msg, mm);
+ break;
+ }
+ case "SystemUpdate:CheckForUpdate": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ this._activeProvider.checkForUpdate();
+ }
+ break;
+ }
+ case "SystemUpdate:StartDownload": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ this._activeProvider.startDownload();
+ }
+ break;
+ }
+ case "SystemUpdate:StopDownload": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ this._activeProvider.stopDownload();
+ }
+ break;
+ }
+ case "SystemUpdate:ApplyUpdate": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ this._activeProvider.applyUpdate();
+ }
+ break;
+ }
+ case "SystemUpdate:SetParameter": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ return this._activeProvider.setParameter(msg.name, msg.value);
+ }
+ break;
+ }
+ case "SystemUpdate:GetParameter": {
+ if (this._isActiveProviderId(msg.uuid)) {
+ return this._activeProvider.getParameter(msg.name);
+ }
+ break;
+ }
+ }
+ },
+
+};
+
+SystemUpdateService.init();