michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict" michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; michael@0: michael@0: this.EXPORTED_SYMBOLS = ["DataStoreChangeNotifier"]; michael@0: michael@0: function debug(s) { michael@0: //dump('DEBUG DataStoreChangeNotifier: ' + s + '\n'); michael@0: } michael@0: michael@0: // DataStoreServiceInternal should not be converted into a lazy getter as it michael@0: // runs code during initialization. michael@0: Cu.import('resource://gre/modules/DataStoreServiceInternal.jsm'); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "ppmm", michael@0: "@mozilla.org/parentprocessmessagemanager;1", michael@0: "nsIMessageBroadcaster"); michael@0: michael@0: this.DataStoreChangeNotifier = { michael@0: children: [], michael@0: messages: [ "DataStore:Changed", "DataStore:RegisterForMessages", michael@0: "DataStore:UnregisterForMessages", michael@0: "child-process-shutdown" ], michael@0: michael@0: init: function() { michael@0: debug("init"); michael@0: michael@0: this.messages.forEach((function(msgName) { michael@0: ppmm.addMessageListener(msgName, this); michael@0: }).bind(this)); michael@0: michael@0: Services.obs.addObserver(this, 'xpcom-shutdown', false); michael@0: }, michael@0: michael@0: observe: function(aSubject, aTopic, aData) { michael@0: debug("observe"); michael@0: michael@0: switch (aTopic) { michael@0: case 'xpcom-shutdown': michael@0: this.messages.forEach((function(msgName) { michael@0: ppmm.removeMessageListener(msgName, this); michael@0: }).bind(this)); michael@0: michael@0: Services.obs.removeObserver(this, 'xpcom-shutdown'); michael@0: ppmm = null; michael@0: break; michael@0: michael@0: default: michael@0: debug("Wrong observer topic: " + aTopic); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: broadcastMessage: function broadcastMessage(aData) { michael@0: debug("Broadast"); michael@0: this.children.forEach(function(obj) { michael@0: if (obj.store == aData.store && obj.owner == aData.owner) { michael@0: obj.mm.sendAsyncMessage("DataStore:Changed:Return:OK", aData); michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: michael@0: receiveMessage: function(aMessage) { michael@0: debug("receiveMessage"); michael@0: michael@0: // No check has to be done when the message is 'child-process-shutdown' michael@0: // because at this point the target is already disconnected from michael@0: // nsFrameMessageManager, so that assertAppHasStatus will always fail. michael@0: let prefName = 'dom.testing.datastore_enabled_for_hosted_apps'; michael@0: if (aMessage.name != 'child-process-shutdown' && michael@0: (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID || michael@0: !Services.prefs.getBoolPref(prefName)) && michael@0: !aMessage.target.assertAppHasStatus(Ci.nsIPrincipal.APP_STATUS_CERTIFIED)) { michael@0: return; michael@0: } michael@0: michael@0: switch (aMessage.name) { michael@0: case "DataStore:Changed": michael@0: this.broadcastMessage(aMessage.data); michael@0: break; michael@0: michael@0: case "DataStore:RegisterForMessages": michael@0: debug("Register!"); michael@0: michael@0: for (let i = 0; i < this.children.length; ++i) { michael@0: if (this.children[i].mm == aMessage.target && michael@0: this.children[i].store == aMessage.data.store && michael@0: this.children[i].owner == aMessage.data.owner) { michael@0: debug("Register on existing index: " + i); michael@0: ++this.children[i].count; michael@0: return; michael@0: } michael@0: } michael@0: michael@0: this.children.push({ mm: aMessage.target, michael@0: store: aMessage.data.store, michael@0: owner: aMessage.data.owner, michael@0: count: 1 }); michael@0: break; michael@0: michael@0: case "child-process-shutdown": michael@0: case "DataStore:UnregisterForMessages": michael@0: debug("Unregister"); michael@0: michael@0: for (let i = 0; i < this.children.length;) { michael@0: if (this.children[i].mm == aMessage.target) { michael@0: debug("Unregister index: " + i); michael@0: if (!--this.children[i].count) { michael@0: debug("Unregister delete index: " + i); michael@0: this.children.splice(i, 1); michael@0: } michael@0: break; michael@0: } else { michael@0: ++i; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: debug("Wrong message: " + aMessage.name); michael@0: } michael@0: } michael@0: } michael@0: michael@0: DataStoreChangeNotifier.init();