mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
Bug 795782 - System Message API: Shouldn't pend messages for running apps to avoid re-firing them when restarting apps. r=fabrice
This commit is contained in:
parent
f118b7b673
commit
f0638f5bc2
@ -16,6 +16,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
// Limit the number of pending messages for a given page.
|
||||
let kMaxPendingMessages;
|
||||
try {
|
||||
@ -25,8 +29,9 @@ try {
|
||||
kMaxPendingMessages = 5;
|
||||
}
|
||||
|
||||
const kMessages =["SystemMessageManager:GetPending",
|
||||
const kMessages =["SystemMessageManager:GetPendingMessages",
|
||||
"SystemMessageManager:Register",
|
||||
"SystemMessageManager:Message:Return:OK",
|
||||
"child-process-shutdown"]
|
||||
|
||||
function debug(aMsg) {
|
||||
@ -46,9 +51,9 @@ function SystemMessageInternal() {
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
Services.obs.addObserver(this, "webapps-registry-ready", false);
|
||||
kMessages.forEach((function(aMsg) {
|
||||
kMessages.forEach(function(aMsg) {
|
||||
ppmm.addMessageListener(aMsg, this);
|
||||
}).bind(this));
|
||||
}, this);
|
||||
}
|
||||
|
||||
SystemMessageInternal.prototype = {
|
||||
@ -64,25 +69,30 @@ SystemMessageInternal.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
|
||||
// Give this message an ID so that we can identify the message and
|
||||
// clean it up from the pending message queue when apps receive it.
|
||||
let messageID = gUUIDGenerator.generateUUID().toString();
|
||||
|
||||
debug("Sending " + aType + " " + JSON.stringify(aMessage) +
|
||||
" for " + aPageURI.spec + " @ " + aManifestURI.spec);
|
||||
if (this._listeners[aManifestURI.spec]) {
|
||||
this._listeners[aManifestURI.spec].forEach(function sendMsg(aListener) {
|
||||
aListener.sendAsyncMessage("SystemMessageManager:Message",
|
||||
{ type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aManifestURI.spec })
|
||||
manifest: aManifestURI.spec,
|
||||
uri: aPageURI.spec,
|
||||
msgID: messageID })
|
||||
});
|
||||
}
|
||||
|
||||
this._pages.forEach(function sendMess_openPage(aPage) {
|
||||
if (aPage.type != aType ||
|
||||
aPage.manifest != aManifestURI.spec ||
|
||||
aPage.uri != aPageURI.spec) {
|
||||
this._pages.forEach(function(aPage) {
|
||||
if (!this._isPageMatched(aPage, aType, aPageURI.spec, aManifestURI.spec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._processPage(aPage, aMessage);
|
||||
}.bind(this))
|
||||
this._openAppPage(aPage, aMessage, messageID);
|
||||
}, this);
|
||||
},
|
||||
|
||||
broadcastMessage: function broadcastMessage(aType, aMessage) {
|
||||
@ -95,6 +105,10 @@ SystemMessageInternal.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give this message an ID so that we can identify the message and
|
||||
// clean it up from the pending message queue when apps receive it.
|
||||
let messageID = gUUIDGenerator.generateUUID().toString();
|
||||
|
||||
debug("Broadcasting " + aType + " " + JSON.stringify(aMessage));
|
||||
// Find pages that registered an handler for this type.
|
||||
this._pages.forEach(function(aPage) {
|
||||
@ -104,12 +118,14 @@ SystemMessageInternal.prototype = {
|
||||
aListener.sendAsyncMessage("SystemMessageManager:Message",
|
||||
{ type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aPage.manifest})
|
||||
manifest: aPage.manifest,
|
||||
uri: aPage.uri,
|
||||
msgID: messageID })
|
||||
});
|
||||
}
|
||||
this._processPage(aPage, aMessage);
|
||||
this._openAppPage(aPage, aMessage, messageID);
|
||||
}
|
||||
}.bind(this))
|
||||
}, this);
|
||||
},
|
||||
|
||||
registerPage: function registerPage(aType, aPageURI, aManifestURI) {
|
||||
@ -120,13 +136,14 @@ SystemMessageInternal.prototype = {
|
||||
this._pages.push({ type: aType,
|
||||
uri: aPageURI.spec,
|
||||
manifest: aManifestURI.spec,
|
||||
pending: [] });
|
||||
pendingMessages: [] });
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
switch(aMessage.name) {
|
||||
case "SystemMessageManager:Register":
|
||||
{
|
||||
let manifest = msg.manifest;
|
||||
debug("Got Register from " + manifest);
|
||||
if (!this._listeners[manifest]) {
|
||||
@ -135,7 +152,9 @@ SystemMessageInternal.prototype = {
|
||||
this._listeners[manifest].push(aMessage.target);
|
||||
debug("listeners for " + manifest + " : " + this._listeners[manifest].length);
|
||||
break;
|
||||
}
|
||||
case "child-process-shutdown":
|
||||
{
|
||||
debug("Got Unregister from " + aMessage.target);
|
||||
let mm = aMessage.target;
|
||||
for (let manifest in this._listeners) {
|
||||
@ -147,41 +166,69 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "SystemMessageManager:GetPending":
|
||||
debug("received SystemMessageManager:GetPending " + aMessage.json.type +
|
||||
" for " + aMessage.json.uri + " @ " + aMessage.json.manifest);
|
||||
// This is a sync call, use to return the pending message for a page.
|
||||
debug(JSON.stringify(msg));
|
||||
// Find the right page.
|
||||
}
|
||||
case "SystemMessageManager:GetPendingMessages":
|
||||
{
|
||||
debug("received SystemMessageManager:GetPendingMessages " + msg.type +
|
||||
" for " + msg.uri + " @ " + msg.manifest);
|
||||
|
||||
// This is a sync call used to return the pending messages for a page.
|
||||
// Find the right page to get its corresponding pending messages.
|
||||
let page = null;
|
||||
this._pages.some(function(aPage) {
|
||||
if (aPage.uri == msg.uri &&
|
||||
aPage.type == msg.type &&
|
||||
aPage.manifest == msg.manifest) {
|
||||
if (this._isPageMatched(aPage, msg.type, msg.uri, msg.manifest)) {
|
||||
page = aPage;
|
||||
}
|
||||
return page !== null;
|
||||
});
|
||||
}, this);
|
||||
if (!page) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let pending = page.pending;
|
||||
// Clear the pending queue for this page.
|
||||
// This is ok since we'll store pending events in SystemMessageManager.js
|
||||
page.pending = [];
|
||||
// Return the |msg| of each pending message (drop the |msgID|).
|
||||
let pendingMessages = [];
|
||||
page.pendingMessages.forEach(function(aMessage) {
|
||||
pendingMessages.push(aMessage.msg);
|
||||
});
|
||||
|
||||
return pending;
|
||||
// Clear the pending queue for this page. This is OK since we'll store
|
||||
// pending messages in the content process (|SystemMessageManager|).
|
||||
page.pendingMessages.length = 0;
|
||||
|
||||
return pendingMessages;
|
||||
break;
|
||||
}
|
||||
case "SystemMessageManager:Message:Return:OK":
|
||||
{
|
||||
debug("received SystemMessageManager:Message:Return:OK " + msg.type +
|
||||
" for " + msg.uri + " @ " + msg.manifest);
|
||||
|
||||
// We need to clean up the pending message since the app has already
|
||||
// received it, thus avoiding the re-lanunched app handling it again.
|
||||
this._pages.forEach(function(aPage) {
|
||||
if (!this._isPageMatched(aPage, msg.type, msg.uri, msg.manifest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pendingMessages = aPage.pendingMessages;
|
||||
for (let i = 0; i < pendingMessages.length; i++) {
|
||||
if (pendingMessages[i].msgID === msg.msgID) {
|
||||
pendingMessages.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "xpcom-shutdown":
|
||||
kMessages.forEach((function(aMsg) {
|
||||
kMessages.forEach(function(aMsg) {
|
||||
ppmm.removeMessageListener(aMsg, this);
|
||||
}).bind(this));
|
||||
}, this);
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
Services.obs.removeObserver(this, "webapps-registry-ready");
|
||||
ppmm = null;
|
||||
@ -192,7 +239,7 @@ SystemMessageInternal.prototype = {
|
||||
// After the webapps' registration has been done for sure,
|
||||
// re-fire the buffered system messages if there is any.
|
||||
this._webappsRegistryReady = true;
|
||||
this._bufferedSysMsgs.forEach((function(aSysMsg) {
|
||||
this._bufferedSysMsgs.forEach(function(aSysMsg) {
|
||||
switch (aSysMsg.how) {
|
||||
case "send":
|
||||
this.sendMessage(
|
||||
@ -202,17 +249,18 @@ SystemMessageInternal.prototype = {
|
||||
this.broadcastMessage(aSysMsg.type, aSysMsg.msg);
|
||||
break;
|
||||
}
|
||||
}).bind(this));
|
||||
}, this);
|
||||
this._bufferedSysMsgs = null;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_processPage: function _processPage(aPage, aMessage) {
|
||||
// Queue the message for the page.
|
||||
aPage.pending.push(aMessage);
|
||||
if (aPage.pending.length > kMaxPendingMessages) {
|
||||
aPage.pending.splice(0, 1);
|
||||
_openAppPage: function _openAppPage(aPage, aMessage, aMessageID) {
|
||||
// Queue the message for this page because we've never known if an app is
|
||||
// opened or not. We'll clean it up when the app has already received it.
|
||||
aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
|
||||
if (aPage.pendingMessages.length > kMaxPendingMessages) {
|
||||
aPage.pendingMessages.splice(0, 1);
|
||||
}
|
||||
|
||||
// We don't need to send the full object to observers.
|
||||
@ -220,10 +268,16 @@ SystemMessageInternal.prototype = {
|
||||
manifest: aPage.manifest,
|
||||
type: aPage.type,
|
||||
target: aMessage.target };
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
|
||||
},
|
||||
|
||||
_isPageMatched: function _isPageMatched(aPage, aType, aUri, aManifest) {
|
||||
return (aPage.type === aType &&
|
||||
aPage.manifest === aManifest &&
|
||||
aPage.uri === aUri)
|
||||
},
|
||||
|
||||
classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
|
||||
|
@ -64,7 +64,8 @@ SystemMessageManager.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
aHandler.handleMessage(wrapped ? aMessage : ObjectWrapper.wrap(aMessage, this._window));
|
||||
aHandler.handleMessage(wrapped ? aMessage
|
||||
: ObjectWrapper.wrap(aMessage, this._window));
|
||||
},
|
||||
|
||||
mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
|
||||
@ -114,7 +115,7 @@ SystemMessageManager.prototype = {
|
||||
|
||||
// Send a sync message to the parent to check if we have a pending message
|
||||
// for this type.
|
||||
let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending",
|
||||
let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPendingMessages",
|
||||
{ type: aType,
|
||||
uri: this._uri,
|
||||
manifest: this._manifest })[0];
|
||||
@ -156,6 +157,15 @@ SystemMessageManager.prototype = {
|
||||
if (msg.manifest != this._manifest)
|
||||
return;
|
||||
|
||||
// Send an acknowledgement to parent to clean up the pending message,
|
||||
// so a re-launched app won't handle it again, which is redundant.
|
||||
cpmm.sendAsyncMessage(
|
||||
"SystemMessageManager:Message:Return:OK",
|
||||
{ type: msg.type,
|
||||
manifest: msg.manifest,
|
||||
uri: msg.uri,
|
||||
msgID: msg.msgID });
|
||||
|
||||
// Bail out if we have no handlers registered for this type.
|
||||
if (!(msg.type in this._handlers)) {
|
||||
debug("No handler for this type");
|
||||
|
Loading…
Reference in New Issue
Block a user