author | Fabrice Desré <fabrice@mozilla.com> |
Wed, 05 Aug 2015 20:30:55 -0700 | |
changeset 256400 | 939e1009ebaf93dfc56fd1ee45d4ecc0a42e4abe |
parent 256399 | 58c131a75dd9a6a0bfaaba50fffa94c5884dd042 |
child 256401 | e200ec9a11fbc3c930c39a613f8186e9028586c6 |
push id | 29175 |
push user | cbook@mozilla.com |
push date | Thu, 06 Aug 2015 10:08:59 +0000 |
treeherder | mozilla-central@725531fc9613 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ferjm |
bugs | 1181930 |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/apps/ImportExport.jsm +++ b/dom/apps/ImportExport.jsm @@ -8,16 +8,17 @@ const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Webapps.jsm"); +Cu.import("resource://gre/modules/MessageBroadcaster.jsm"); Cu.importGlobalProperties(['File']); XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); @@ -470,20 +471,20 @@ this.ImportExport = { meta); // Save the app registry, and sends the various notifications. // TODO: stop accessing internal methods of other objects. yield DOMApplicationRegistry._saveApps(); app = AppsUtils.cloneAppObject(meta); app.manifest = manifest; - DOMApplicationRegistry.broadcastMessage("Webapps:AddApp", - { id: meta.id, app: app }); - DOMApplicationRegistry.broadcastMessage("Webapps:Install:Return:OK", - { app: app }); + MessageBroadcaster.broadcastMessage("Webapps:AddApp", + { id: meta.id, app: app }); + MessageBroadcaster.broadcastMessage("Webapps:Install:Return:OK", + { app: app }); Services.obs.notifyObservers(null, "webapps-installed", JSON.stringify({ manifestURL: meta.manifestURL })); } catch(e) { debug("Import failed: " + e); if (appDir && appDir.exists()) { appDir.remove(true); }
new file mode 100644 --- /dev/null +++ b/dom/apps/MessageBroadcaster.jsm @@ -0,0 +1,132 @@ +/* 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"; + +// Manages registration of message managers from child processes and +// broadcasting messages to them. + +this.EXPORTED_SYMBOLS = ["MessageBroadcaster"]; + +this.MessageBroadcaster = { + appGetter: null, + children: [], + + init: function(aAppGetter) { + if (!aAppGetter || typeof aAppGetter !== "function") { + throw "MessageBroadcaster.init needs a function parameter"; + } + this.appGetter = aAppGetter; + }, + + // We manage refcounting of listeners per message manager. + addMessageListener: function(aMsgNames, aApp, aMm) { + aMsgNames.forEach(aMsgName => { + let manifestURL = aApp && aApp.manifestURL; + if (!(aMsgName in this.children)) { + this.children[aMsgName] = []; + } + + let mmFound = this.children[aMsgName].some(mmRef => { + if (mmRef.mm === aMm) { + mmRef.refCount++; + return true; + } + return false; + }); + + if (!mmFound) { + this.children[aMsgName].push({ + mm: aMm, + refCount: 1 + }); + } + + // If the state reported by the registration is outdated, update it now. + if (manifestURL && ((aMsgName === 'Webapps:FireEvent') || + (aMsgName === 'Webapps:UpdateState'))) { + let app = this.appGetter(aApp.manifestURL); + if (app && ((aApp.installState !== app.installState) || + (aApp.downloading !== app.downloading))) { + debug("Got a registration from an outdated app: " + + manifestURL); + let aEvent ={ + type: app.installState, + app: app, + manifestURL: app.manifestURL, + manifest: app.manifest + }; + aMm.sendAsyncMessage(aMsgName, aEvent); + } + } + }); + }, + + removeMessageListener: function(aMsgNames, aMm) { + if (aMsgNames.length === 1 && + aMsgNames[0] === "Webapps:Internal:AllMessages") { + for (let msgName in this.children) { + let msg = this.children[msgName]; + + for (let mmI = msg.length - 1; mmI >= 0; mmI -= 1) { + let mmRef = msg[mmI]; + if (mmRef.mm === aMm) { + msg.splice(mmI, 1); + } + } + + if (msg.length === 0) { + delete this.children[msgName]; + } + } + return; + } + + aMsgNames.forEach(aMsgName => { + if (!(aMsgName in this.children)) { + return; + } + + let removeIndex; + this.children[aMsgName].some((mmRef, index) => { + if (mmRef.mm === aMm) { + mmRef.refCount--; + if (mmRef.refCount === 0) { + removeIndex = index; + } + return true; + } + return false; + }); + + if (removeIndex) { + this.children[aMsgName].splice(removeIndex, 1); + } + }); + }, + + // Some messages can be listened by several content processes: + // Webapps:AddApp + // Webapps:RemoveApp + // Webapps:Install:Return:OK + // Webapps:Uninstall:Return:OK + // Webapps:Uninstall:Broadcast:Return:OK + // Webapps:FireEvent + // Webapps:checkForUpdate:Return:OK + // Webapps:UpdateState + broadcastMessage: function(aMsgName, aContent) { + if (!(aMsgName in this.children)) { + return; + } + this.children[aMsgName].forEach((mmRef) => { + mmRef.mm.sendAsyncMessage(aMsgName, this.formatMessage(aContent)); + }); + }, + + formatMessage: function(aData) { + let msg = aData; + delete msg["mm"]; + return msg; + }, +}
--- a/dom/apps/Webapps.jsm +++ b/dom/apps/Webapps.jsm @@ -37,16 +37,17 @@ Cu.import("resource://gre/modules/XPCOMU Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import('resource://gre/modules/ActivitiesService.jsm'); Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/AppDownloadManager.jsm"); Cu.import("resource://gre/modules/osfile.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); +Cu.import("resource://gre/modules/MessageBroadcaster.jsm"); XPCOMUtils.defineLazyGetter(this, "UserCustomizations", function() { let enabled = false; try { enabled = Services.prefs.getBoolPref("dom.apps.customization.enabled"); } catch(e) {} if (enabled) { @@ -190,17 +191,16 @@ this.DOMApplicationRegistry = { get kPackaged() "packaged", get kHosted() "hosted", get kHostedAppcache() "hosted-appcache", get kTrustedHosted() "hosted-trusted", // Path to the webapps.json file where we store the registry data. appsFile: null, webapps: { }, - children: [ ], allAppsLaunchable: false, _updateHandlers: [ ], _pendingUninstalls: {}, _contentActions: new Map(), dirKey: DIRECTORY_NAME, init: function() { // Keep the messages in sync with the lazy-loading in browser.js (bug 1171013). @@ -246,19 +246,21 @@ this.DOMApplicationRegistry = { AppDownloadManager.registerCancelFunction(this.cancelDownload.bind(this)); this.appsFile = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], true).path; this.loadAndUpdateApps(); - Langpacks.registerRegistryFunctions(this.broadcastMessage.bind(this), + Langpacks.registerRegistryFunctions(MessageBroadcaster.broadcastMessage.bind(MessageBroadcaster), this._appIdForManifestURL.bind(this), this.getFullAppByManifestURL.bind(this)); + + MessageBroadcaster.init(this.getAppByManifestURL); }, // loads the current registry, that could be empty on first run. loadCurrentRegistry: function() { return AppsUtils.loadJSONAsync(this.appsFile).then((aData) => { if (!aData) { return; } @@ -1175,103 +1177,16 @@ this.DOMApplicationRegistry = { cpmm = null; ppmm = null; } else if (aTopic == "memory-pressure") { // Clear the manifest cache on memory pressure. this._manifestCache = {}; } }, - addMessageListener: function(aMsgNames, aApp, aMm) { - aMsgNames.forEach(function (aMsgName) { - let man = aApp && aApp.manifestURL; - if (!(aMsgName in this.children)) { - this.children[aMsgName] = []; - } - - let mmFound = this.children[aMsgName].some(function(mmRef) { - if (mmRef.mm === aMm) { - mmRef.refCount++; - return true; - } - return false; - }); - - if (!mmFound) { - this.children[aMsgName].push({ - mm: aMm, - refCount: 1 - }); - } - - // If the state reported by the registration is outdated, update it now. - if ((aMsgName === 'Webapps:FireEvent') || - (aMsgName === 'Webapps:UpdateState')) { - if (man) { - let app = this.getAppByManifestURL(aApp.manifestURL); - if (app && ((aApp.installState !== app.installState) || - (aApp.downloading !== app.downloading))) { - debug("Got a registration from an outdated app: " + - aApp.manifestURL); - let aEvent ={ - type: app.installState, - app: app, - manifestURL: app.manifestURL, - manifest: app.manifest - }; - aMm.sendAsyncMessage(aMsgName, aEvent); - } - } - } - }, this); - }, - - removeMessageListener: function(aMsgNames, aMm) { - if (aMsgNames.length === 1 && - aMsgNames[0] === "Webapps:Internal:AllMessages") { - for (let msgName in this.children) { - let msg = this.children[msgName]; - - for (let mmI = msg.length - 1; mmI >= 0; mmI -= 1) { - let mmRef = msg[mmI]; - if (mmRef.mm === aMm) { - msg.splice(mmI, 1); - } - } - - if (msg.length === 0) { - delete this.children[msgName]; - } - } - return; - } - - aMsgNames.forEach(function(aMsgName) { - if (!(aMsgName in this.children)) { - return; - } - - let removeIndex; - this.children[aMsgName].some(function(mmRef, index) { - if (mmRef.mm === aMm) { - mmRef.refCount--; - if (mmRef.refCount === 0) { - removeIndex = index; - } - return true; - } - return false; - }); - - if (removeIndex) { - this.children[aMsgName].splice(removeIndex, 1); - } - }, this); - }, - formatMessage: function(aData) { let msg = aData; delete msg["mm"]; return msg; }, receiveMessage: function(aMessage) { // nsIPrefBranch throws if pref does not exist, faster to simply write @@ -1344,23 +1259,23 @@ this.DOMApplicationRegistry = { this.notifyAppsRegistryReady(); break; case "Webapps:GetList": // GetList is special because it's synchronous. So far so well, it's the // only synchronous message, if we get more at some point they should get // this treatment also. return this.doGetList(); case "child-process-shutdown": - this.removeMessageListener(["Webapps:Internal:AllMessages"], mm); + MessageBroadcaster.removeMessageListener(["Webapps:Internal:AllMessages"], mm); break; case "Webapps:RegisterForMessages": - this.addMessageListener(msg.messages, msg.app, mm); + MessageBroadcaster.addMessageListener(msg.messages, msg.app, mm); break; case "Webapps:UnregisterForMessages": - this.removeMessageListener(msg, mm); + MessageBroadcaster.removeMessageListener(msg, mm); break; default: processedImmediately = false; } if (processedImmediately) { return; } @@ -1455,34 +1370,16 @@ this.DOMApplicationRegistry = { } }); }, getAppInfo: function getAppInfo(aAppId) { return AppsUtils.getAppInfo(this.webapps, aAppId); }, - // Some messages can be listened by several content processes: - // Webapps:AddApp - // Webapps:RemoveApp - // Webapps:Install:Return:OK - // Webapps:Uninstall:Return:OK - // Webapps:Uninstall:Broadcast:Return:OK - // Webapps:FireEvent - // Webapps:checkForUpdate:Return:OK - // Webapps:UpdateState - broadcastMessage: function broadcastMessage(aMsgName, aContent) { - if (!(aMsgName in this.children)) { - return; - } - this.children[aMsgName].forEach((mmRef) => { - mmRef.mm.sendAsyncMessage(aMsgName, this.formatMessage(aContent)); - }); - }, - registerUpdateHandler: function(aHandler) { this._updateHandlers.push(aHandler); }, unregisterUpdateHandler: function(aHandler) { let index = this._updateHandlers.indexOf(aHandler); if (index != -1) { this._updateHandlers.splice(index, 1); @@ -1749,26 +1646,26 @@ this.DOMApplicationRegistry = { // Ensure we don't send additional errors for this download app.isCanceling = true; // Ensure this app can be downloaded again after canceling app.downloading = false; this._saveApps().then(() => { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: { progress: 0, installState: download.previousState, downloading: false }, error: error, id: app.id }) - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", manifestURL: app.manifestURL }); }); AppDownloadManager.remove(aManifestURL); }, startDownload: Task.async(function*(aManifestURL) { @@ -1785,21 +1682,21 @@ this.DOMApplicationRegistry = { if (app.downloading) { debug("app is already downloading. Ignoring."); throw new Error("APP_IS_DOWNLOADING"); } // If the caller is trying to start a download but we have nothing to // download, send an error. if (!app.downloadAvailable) { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { error: "NO_DOWNLOAD_AVAILABLE", id: app.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", manifestURL: app.manifestURL }); throw new Error("NO_DOWNLOAD_AVAILABLE"); } // First of all, we check if the download is supposed to update an // already installed application. @@ -1833,22 +1730,22 @@ this.DOMApplicationRegistry = { } else { // Hosted app with no appcache, nothing to do, but we fire a // downloaded event. debug("No appcache found, sending 'downloaded' for " + aManifestURL); app.downloadAvailable = false; yield this._saveApps(); - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, manifest: jsonManifest, id: app.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadsuccess", manifestURL: aManifestURL }); } return; } @@ -1886,21 +1783,21 @@ this.DOMApplicationRegistry = { app = this.webapps[id]; // Set state and fire events. app.downloading = false; app.downloadAvailable = false; app.readyToApplyDownload = true; app.updateTime = Date.now(); - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, id: app.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadsuccess", manifestURL: aManifestURL }); if (app.installState == "pending") { // We restarted a failed download, apply it automatically. this.applyDownload(aManifestURL); } }), @@ -2007,22 +1904,22 @@ this.DOMApplicationRegistry = { { manifest: newManifest, origin: app.origin, manifestURL: app.manifestURL, kind: app.kind }, true); } this.updateDataStore(this.webapps[id].localId, app.origin, app.manifestURL, newManifest); - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, manifest: newManifest, id: app.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadapplied", manifestURL: app.manifestURL }); }), startOfflineCacheDownload: function(aManifest, aApp, aProfileDir, aIsUpdate) { debug("startOfflineCacheDownload " + aApp.id + " " + aApp.kind); if ((aApp.kind !== this.kHostedAppcache && @@ -2045,17 +1942,17 @@ this.DOMApplicationRegistry = { aApp.installState = "updating"; } // We set the 'downloading' flag and update the apps registry right before // starting the app download/update. aApp.downloading = true; aApp.progress = 0; DOMApplicationRegistry._saveApps().then(() => { - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { // Clear any previous errors. error: null, app: { downloading: true, installState: aApp.installState, progress: 0 }, id: aApp.id @@ -2186,21 +2083,21 @@ this.DOMApplicationRegistry = { // "downloadapplied". let updateObserver = { observe: function(aSubject, aTopic, aObsData) { debug("onlyCheckAppCache updateSvc.checkForUpdate return for " + app.manifestURL + " - event is " + aTopic); if (aTopic == "offline-cache-update-available") { app.downloadAvailable = true; this._saveApps().then(() => { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, id: app.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadavailable", manifestURL: app.manifestURL, requestID: aData.requestID }); }); } else { sendError("NOT_UPDATABLE"); } @@ -2386,21 +2283,21 @@ this.DOMApplicationRegistry = { // event. aApp.downloadAvailable = true; aApp.downloadSize = manifest.size; aApp.updateManifest = aNewManifest; this._saveWidgetsFullPath(manifest, aApp); yield this._saveApps(); - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, id: aApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadavailable", manifestURL: aApp.manifestURL, requestID: aData.requestID }); }), // A hosted app is updated if the app manifest or the appcache needs // updating. Even if the app manifest has not changed, we still check @@ -2418,22 +2315,22 @@ this.DOMApplicationRegistry = { aApp.manifest = aNewManifest || aOldManifest; let manifest = new ManifestHelper(aApp.manifest, aApp.origin, aApp.manifestURL); aApp.role = manifest.role || ""; if (!AppsUtils.checkAppRole(aApp.role, aApp.appStatus)) { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: aApp.manifest, id: aApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadapplied", manifestURL: aApp.manifestURL, requestID: aData.requestID }); delete aApp.manifest; return; } @@ -2469,22 +2366,22 @@ this.DOMApplicationRegistry = { // Update the registry. this.webapps[aId] = aApp; yield this._saveApps(); if ((aApp.kind !== this.kHostedAppcache && aApp.kind !== this.kTrustedHosted) || !aApp.manifest.appcache_path) { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: aApp.manifest, id: aApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloadapplied", manifestURL: aApp.manifestURL, requestID: aData.requestID }); } else { // Check if the appcache is updatable, and send "downloadavailable" or // "downloadapplied". debug("updateHostedApp: updateSvc.checkForUpdate for " + @@ -2503,22 +2400,22 @@ this.DOMApplicationRegistry = { let eventType = topic == "offline-cache-update-available" ? "downloadavailable" : "downloadapplied"; aApp.downloadAvailable = (eventType == "downloadavailable"); yield this._saveApps(); - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: aApp.manifest, id: aApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: eventType, manifestURL: aApp.manifestURL, requestID: aData.requestID }); } delete aApp.manifest; }), @@ -3045,17 +2942,17 @@ this.DOMApplicationRegistry = { // Store the manifest and the updateManifest. this._writeManifestFile(app.id, false, aManifest); if (aUpdateManifest) { this._writeManifestFile(app.id, true, aUpdateManifest); } this._saveApps().then(() => { - this.broadcastMessage("Webapps:AddApp", + MessageBroadcaster.broadcastMessage("Webapps:AddApp", { id: app.id, app: app, manifest: aManifest }); }); }), confirmInstall: Task.async(function*(aData, aProfileDir, aInstallSuccessCallback) { debug("confirmInstall"); let origin = Services.io.newURI(aData.app.origin, null, null); @@ -3161,17 +3058,17 @@ this.DOMApplicationRegistry = { // We notify about the successful installation via mgmt.oninstall and the // corresponding DOMRequest.onsuccess event as soon as the app is properly // saved in the registry. yield this._saveApps(); aData.isPackage ? appObject.updateManifest = jsonManifest : appObject.manifest = jsonManifest; - this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject }); + MessageBroadcaster.broadcastMessage("Webapps:AddApp", { id: id, app: appObject }); if (!aData.isPackage) { this.updateAppHandlers(null, app.manifest, app); if (aInstallSuccessCallback) { try { yield aInstallSuccessCallback(app, app.manifest); } catch (e) { // Ignore exceptions during the local installation of @@ -3186,17 +3083,17 @@ this.DOMApplicationRegistry = { // Skip directly to onInstallSuccessAck, since there isn't // a WebappsRegistry to receive Webapps:Install:Return:OK and respond // Webapps:Install:Return:Ack when an app is being auto-installed. this.onInstallSuccessAck(app.manifestURL); } else { // Broadcast Webapps:Install:Return:OK so the WebappsRegistry can notify // the installing page about the successful install, after which it'll // respond Webapps:Install:Return:Ack, which calls onInstallSuccessAck. - this.broadcastMessage("Webapps:Install:Return:OK", aData); + MessageBroadcaster.broadcastMessage("Webapps:Install:Return:OK", aData); } Services.obs.notifyObservers(null, "webapps-installed", JSON.stringify({ manifestURL: app.manifestURL })); if (aData.forceSuccessAck) { // If it's a local install, there's no content process so just // ack the install. @@ -3243,17 +3140,17 @@ this.DOMApplicationRegistry = { yield this._saveApps(); this.updateAppHandlers(null, aManifest, aNewApp); // Clear the manifest cache in case it holds the update manifest. if (aId in this._manifestCache) { delete this._manifestCache[aId]; } - this.broadcastMessage("Webapps:AddApp", + MessageBroadcaster.broadcastMessage("Webapps:AddApp", { id: aId, app: aNewApp, manifest: aManifest }); Services.obs.notifyObservers(null, "webapps-installed", JSON.stringify({ manifestURL: aNewApp.manifestURL })); if (supportUseCurrentProfile()) { // Update the permissions for this app. PermissionsInstaller.installPermissions({ manifest: aManifest, @@ -3271,29 +3168,29 @@ this.DOMApplicationRegistry = { yield aInstallSuccessCallback(aNewApp, aManifest, zipFile.path); } catch (e) { // Ignore exceptions during the local installation of // an app. If it fails, the app will anyway be considered // as not installed because isLaunchable will return false. } } - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, manifest: aManifest, manifestURL: aNewApp.manifestURL }); // Check if we have asm.js code to preload for this application. yield ScriptPreloader.preload(aNewApp, aManifest); // Update langpack information. yield Langpacks.register(aNewApp, aManifest); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: ["downloadsuccess", "downloadapplied"], manifestURL: aNewApp.manifestURL }); }), _nextLocalId: function() { let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1; @@ -3404,17 +3301,17 @@ this.DOMApplicationRegistry = { // initialize the progress to 0 right now aOldApp.progress = 0; // Save the current state of the app to handle cases where we may be // retrying a past download. yield DOMApplicationRegistry._saveApps(); - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { // Clear any previous download errors. error: null, app: aOldApp, id: aId }); let zipFile = yield this._getPackage(requestChannel, aId, aOldApp, aNewApp); @@ -3573,23 +3470,23 @@ this.DOMApplicationRegistry = { throw Cr.NS_ERROR_NOT_IMPLEMENTED; } }; return requestChannel; }, _sendDownloadProgressEvent: function(aNewApp, aProgress) { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: { progress: aProgress }, id: aNewApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "progress", manifestURL: aNewApp.manifestURL }); }, _getPackage: function(aRequestChannel, aId, aOldApp, aNewApp) { let deferred = Promise.defer(); @@ -3687,21 +3584,21 @@ this.DOMApplicationRegistry = { staged.moveTo(staged.parent, "update.webapp"); } catch (ex) { // We don't really mind much if this fails. } } // Save the updated registry, and cleanup the tmp directory. this._saveApps().then(() => { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, id: aApp.id }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { manifestURL: aApp.manifestURL, eventType: ["downloadsuccess", "downloadapplied"] }); }); let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false); if (file && file.exists()) { file.remove(true); } @@ -4035,17 +3932,17 @@ this.DOMApplicationRegistry = { delete this.webapps[oldId]; // Rename the directories where the files are installed. [DIRECTORY_NAME, "TmpD"].forEach(function(aDir) { let parent = FileUtils.getDir(aDir, ["webapps"], true, true); let dir = FileUtils.getDir(aDir, ["webapps", oldId], true, true); dir.moveTo(parent, newId); }); // Signals that we need to swap the old id with the new app. - this.broadcastMessage("Webapps:UpdateApp", { oldId: oldId, + MessageBroadcaster.broadcastMessage("Webapps:UpdateApp", { oldId: oldId, newId: newId, app: aOldApp }); } } }, _getIds: function(aIsSigned, aZipReader, aConverter, aNewApp, aOldApp, @@ -4147,22 +4044,22 @@ this.DOMApplicationRegistry = { // Erase the .staged properties only if there's no download available // anymore. if (!aOldApp.downloadAvailable && aOldApp.staged) { delete aOldApp.staged; } this._saveApps().then(() => { - this.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aOldApp, error: aError, id: aId }); - this.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", manifestURL: aNewApp.manifestURL }); }); AppDownloadManager.remove(aNewApp.manifestURL); }, doUninstall: Task.async(function*(aData, aMm) { @@ -4231,18 +4128,18 @@ this.DOMApplicationRegistry = { try { dir.remove(true); } catch (e) {} delete this.webapps[id]; yield this._saveApps(); - this.broadcastMessage("Webapps:Uninstall:Broadcast:Return:OK", aApp); - this.broadcastMessage("Webapps:RemoveApp", { id: id }); + MessageBroadcaster.broadcastMessage("Webapps:Uninstall:Broadcast:Return:OK", aApp); + MessageBroadcaster.broadcastMessage("Webapps:RemoveApp", { id: id }); return aApp; }), _promptForUninstall: function(aData) { let deferred = Promise.defer(); this._pendingUninstalls[aData.requestID] = deferred; Services.obs.notifyObservers(null, "webapps-ask-uninstall", @@ -4652,21 +4549,21 @@ this.DOMApplicationRegistry = { if (!id || !this.webapps[id]) { return; } debug("Enabling " + id); let app = this.webapps[id]; app.enabled = aData.enabled; this._saveApps().then(() => { - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, id: app.id }); - this.broadcastMessage("Webapps:SetEnabled:Return", app); + MessageBroadcaster.broadcastMessage("Webapps:SetEnabled:Return", app); }); // Update customization. this.getManifestFor(app.manifestURL).then((aManifest) => { app.enabled ? UserCustomizations.register(aManifest, app) : UserCustomizations.unregister(aManifest, app); }); }, @@ -4876,21 +4773,21 @@ let AppcacheObserver = function(aApp) { // Send a first progress event to correctly set the DOM object's properties. this._sendProgressEvent(); }; AppcacheObserver.prototype = { // nsIOfflineCacheUpdateObserver implementation _sendProgressEvent: function() { let app = this.app; - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, id: app.id }); - DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "progress", manifestURL: app.manifestURL }); }, updateStateChanged: function appObs_Update(aUpdate, aState) { let mustSave = false; let app = this.app; @@ -4908,21 +4805,21 @@ AppcacheObserver.prototype = { if (aStatus != "installed") { self._sendProgressEvent(); return; } app.updateTime = Date.now(); app.downloading = false; app.downloadAvailable = false; - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, id: app.id }); - DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: ["downloadsuccess", "downloadapplied"], manifestURL: app.manifestURL }); } let setError = function appObs_setError(aError) { debug("Offlinecache setError to " + aError); app.downloading = false; @@ -4930,22 +4827,22 @@ AppcacheObserver.prototype = { // If we are canceling the download, we already send a DOWNLOAD_CANCELED // error. if (app.isCanceling) { delete app.isCanceling; return; } - DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: app, error: aError, id: app.id }); - DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: "downloaderror", manifestURL: app.manifestURL }); } switch (aState) { case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR: aUpdate.removeObserver(this);
--- a/dom/apps/moz.build +++ b/dom/apps/moz.build @@ -29,16 +29,17 @@ EXTRA_COMPONENTS += [ 'Webapps.manifest', ] EXTRA_JS_MODULES += [ 'AppDownloadManager.jsm', 'AppsServiceChild.jsm', 'FreeSpaceWatcher.jsm', 'Langpacks.jsm', + 'MessageBroadcaster.jsm', 'OfflineCacheInstaller.jsm', 'PermissionsInstaller.jsm', 'PermissionsTable.jsm', 'StoreTrustAnchor.jsm', 'UserCustomizations.jsm', ] EXTRA_PP_JS_MODULES += [
--- a/toolkit/devtools/server/actors/webapps.js +++ b/toolkit/devtools/server/actors/webapps.js @@ -207,16 +207,17 @@ PackageUploadBulkActor.prototype.request function WebappsActor(aConnection) { debug("init"); // Load actor dependencies lazily as this actor require extra environnement // preparation to work (like have a profile setup in xpcshell tests) Cu.import("resource://gre/modules/Webapps.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); + Cu.import("resource://gre/modules/MessageBroadcaster.jsm"); // Keep reference of already connected app processes. // values: app frame message manager this._connectedApps = new Set(); this.conn = aConnection; this._uploads = []; this._actorPool = new ActorPool(this.conn); @@ -284,27 +285,27 @@ WebappsActor.prototype = { if (aApp.kind == undefined) { aApp.kind = manifest.appcache_path ? reg.kHostedAppcache : reg.kHosted; } // Needed to evict manifest cache on content side // (has to be dispatched first, otherwise other messages like // Install:Return:OK are going to use old manifest version) - reg.broadcastMessage("Webapps:UpdateState", { + MessageBroadcaster.broadcastMessage("Webapps:UpdateState", { app: aApp, manifest: manifest, id: aApp.id }); - reg.broadcastMessage("Webapps:FireEvent", { + MessageBroadcaster.broadcastMessage("Webapps:FireEvent", { eventType: ["downloadsuccess", "downloadapplied"], manifestURL: aApp.manifestURL }); - reg.broadcastMessage("Webapps:AddApp", { id: aId, app: aApp }); - reg.broadcastMessage("Webapps:Install:Return:OK", { + MessageBroadcaster.broadcastMessage("Webapps:AddApp", { id: aId, app: aApp }); + MessageBroadcaster.broadcastMessage("Webapps:Install:Return:OK", { app: aApp, oid: "foo", requestID: "bar" }); Services.obs.notifyObservers(null, "webapps-installed", JSON.stringify({ manifestURL: aApp.manifestURL }));