Bug 1018320 - RequestSync API - patch 3 - a Promise return value from sendAsyncMessage, r=fabrice

This commit is contained in:
Andrea Marchesini 2015-01-13 09:53:18 +00:00
parent 717717cd09
commit b052341e26
3 changed files with 97 additions and 18 deletions

View File

@ -46,6 +46,7 @@ const kMessages =["SystemMessageManager:GetPendingMessages",
"SystemMessageManager:Message:Return:OK",
"SystemMessageManager:AskReadyToRegister",
"SystemMessageManager:HandleMessagesDone",
"SystemMessageManager:HandleMessageDone",
"child-process-shutdown"]
function debug(aMsg) {
@ -84,6 +85,8 @@ function SystemMessageInternal() {
this._configurators = {};
this._pendingPromises = new Map();
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, "webapps-registry-start", false);
Services.obs.addObserver(this, "webapps-registry-ready", false);
@ -176,6 +179,14 @@ SystemMessageInternal.prototype = {
},
sendMessage: function(aType, aMessage, aPageURI, aManifestURI, aExtra) {
return new Promise((aResolve, aReject) => {
this.sendMessageInternal(aType, aMessage, aPageURI, aManifestURI, aExtra,
aResolve, aReject);
});
},
sendMessageInternal: function(aType, aMessage, aPageURI, aManifestURI,
aExtra, aResolvePromiseCb, aRejectPromiseCb) {
// Buffer system messages until the webapps' registration is ready,
// so that we can know the correct pages registered to be sent.
if (!this._webappsRegistryReady) {
@ -184,15 +195,22 @@ SystemMessageInternal.prototype = {
msg: aMessage,
pageURI: aPageURI,
manifestURI: aManifestURI,
extra: aExtra });
extra: aExtra,
resolvePromiseCb: aResolvePromiseCb,
rejectPromiseCb: aRejectPromiseCb });
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();
let manifestURL = aManifestURI.spec;
let pendingPromise = { resolvePromiseCb: aResolvePromiseCb,
rejectPromiseCb: aRejectPromiseCb,
manifestURL: manifestURL,
counter: 0 };
let pageURLs = [];
if (aPageURI) {
pageURLs.push(aPageURI.spec);
@ -226,6 +244,9 @@ SystemMessageInternal.prototype = {
return;
}
// For each page we must receive a confirm.
++pendingPromise.counter;
let page = this._findPage(aType, aPageURL, manifestURL);
if (page) {
// Queue this message in the corresponding pages.
@ -233,7 +254,12 @@ SystemMessageInternal.prototype = {
this._openAppPage(page, aMessage, aExtra, result);
}
}, this);
if (pendingPromise.counter) {
this._pendingPromises.set(messageID, pendingPromise);
}
},
broadcastMessage: function(aType, aMessage, aExtra) {
@ -393,7 +419,8 @@ SystemMessageInternal.prototype = {
"SystemMessageManager:GetPendingMessages",
"SystemMessageManager:HasPendingMessages",
"SystemMessageManager:Message:Return:OK",
"SystemMessageManager:HandleMessagesDone"].indexOf(aMessage.name) != -1) {
"SystemMessageManager:HandleMessagesDone",
"SystemMessageManager:HandleMessageDone"].indexOf(aMessage.name) != -1) {
if (!aMessage.target.assertContainApp(msg.manifestURL)) {
debug("Got message from a child process containing illegal manifest URL.");
return null;
@ -442,6 +469,8 @@ SystemMessageInternal.prototype = {
manifestURL,
true,
null);
this._rejectPendingPromises(manifestURL);
}
break;
}
@ -453,6 +482,7 @@ SystemMessageInternal.prototype = {
msg.manifestURL,
false,
msg.pageURL);
this._rejectPendingPromises(msg.manifestURL);
break;
}
case "SystemMessageManager:GetPendingMessages":
@ -520,6 +550,21 @@ SystemMessageInternal.prototype = {
}
break;
}
case "SystemMessageManager:HandleMessageDone":
{
debug("received SystemMessageManager:HandleMessageDone " + msg.type +
" with msgID " + msg.msgID + " for " + msg.pageURL +
" @ " + msg.manifestURL);
// Maybe this should resolve a pending promise.
this._resolvePendingPromises(msg.msgID);
// A page has finished handling some of its system messages, so we try
// to release the CPU wake lock we acquired on behalf of that page.
this._releaseCpuWakeLock(this._createKeyForPage(msg), 1);
break;
}
case "SystemMessageManager:HandleMessagesDone":
{
debug("received SystemMessageManager:HandleMessagesDone " + msg.type +
@ -547,6 +592,7 @@ SystemMessageInternal.prototype = {
ppmm = null;
this._pages = null;
this._bufferedSysMsgs = null;
this._pendingPromises.clear();
break;
case "webapps-registry-start":
this._webappsRegistryReady = false;
@ -558,9 +604,10 @@ SystemMessageInternal.prototype = {
this._bufferedSysMsgs.forEach(function(aSysMsg) {
switch (aSysMsg.how) {
case "send":
this.sendMessage(
this.sendMessageInternal(
aSysMsg.type, aSysMsg.msg,
aSysMsg.pageURI, aSysMsg.manifestURI, aSysMsg.extra);
aSysMsg.pageURI, aSysMsg.manifestURI, aSysMsg.extra,
aSysMsg.resolvePromiseCb, aSysMsg.rejectPromiseCb);
break;
case "broadcast":
this.broadcastMessage(aSysMsg.type, aSysMsg.msg, aSysMsg.extra);
@ -596,6 +643,9 @@ SystemMessageInternal.prototype = {
" from registered pages due to app uninstallation.");
}
}
this._rejectPendingPromises(manifestURL);
debug("Finish updating registered pages for an uninstalled app.");
break;
}
@ -692,9 +742,10 @@ SystemMessageInternal.prototype = {
appPageIsRunning = true;
// We need to acquire a CPU wake lock for that page and expect that
// we'll receive a "SystemMessageManager:HandleMessagesDone" message
// when the page finishes handling the system message. At that point,
// we'll release the lock we acquired.
// we'll receive a "SystemMessageManager:HandleMessagesDone" or a
// "SystemMessageManager:HandleMessageDone" message when the page
// finishes handling the system message. At that point, we'll release
// the lock we acquired.
this._acquireCpuWakeLock(pageKey);
// Multiple windows can share the same target (process), the content
@ -714,8 +765,9 @@ SystemMessageInternal.prototype = {
// The app page isn't running and relies on the 'open-app' chrome event to
// wake it up. We still need to acquire a CPU wake lock for that page and
// expect that we will receive a "SystemMessageManager:HandleMessagesDone"
// message when the page finishes handling the system message with other
// pending messages. At that point, we'll release the lock we acquired.
// or a "SystemMessageManager:HandleMessageDone" message when the page
// finishes handling the system message with other pending messages. At
// that point, we'll release the lock we acquired.
this._acquireCpuWakeLock(pageKey);
return MSG_SENT_FAILURE_APP_NOT_RUNNING;
} else {
@ -724,6 +776,28 @@ SystemMessageInternal.prototype = {
},
_resolvePendingPromises: function(aMessageID) {
if (!this._pendingPromises.has(aMessageID)) {
debug("Unknown pendingPromise messageID. This seems a bug!!");
return;
}
let obj = this._pendingPromises.get(aMessageID);
if (!--obj.counter) {
obj.resolvePromiseCb();
this._pendingPromises.delete(aMessageID);
}
},
_rejectPendingPromises: function(aManifestURL) {
for (var [i, obj] of this._pendingPromises) {
if (obj.manifestURL == aManifestURL) {
obj.rejectPromiseCb();
this._pendingPromises.delete(i);
}
}
},
classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal,

View File

@ -57,7 +57,7 @@ function SystemMessageManager() {
SystemMessageManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_dispatchMessage: function(aType, aDispatcher, aMessage) {
_dispatchMessage: function(aType, aDispatcher, aMessage, aMessageID) {
if (aDispatcher.isHandling) {
// Queue up the incomming message if we're currently dispatching a
// message; we'll send the message once we finish with the current one.
@ -66,7 +66,7 @@ SystemMessageManager.prototype = {
// event loop from within a system message handler (e.g. via alert()),
// and we can then try to send the page another message while it's
// inside this nested event loop.
aDispatcher.messages.push(aMessage);
aDispatcher.messages.push({ message: aMessage, messageID: aMessageID });
return;
}
@ -96,16 +96,17 @@ SystemMessageManager.prototype = {
// We need to notify the parent one of the system messages has been handled,
// so the parent can release the CPU wake lock it took on our behalf.
cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
cpmm.sendAsyncMessage("SystemMessageManager:HandleMessageDone",
{ type: aType,
manifestURL: this._manifestURL,
pageURL: this._pageURL,
handledCount: 1 });
msgID: aMessageID });
aDispatcher.isHandling = false;
if (aDispatcher.messages.length > 0) {
this._dispatchMessage(aType, aDispatcher, aDispatcher.messages.shift());
let msg = aDispatcher.messages.shift();
this._dispatchMessage(aType, aDispatcher, msg.message, msg.messageID);
} else {
// No more messages that need to be handled, we can notify the
// ContentChild to release the CPU wake lock grabbed by the ContentParent
@ -236,8 +237,9 @@ SystemMessageManager.prototype = {
}
messages.forEach(function(aMsg) {
this._dispatchMessage(msg.type, dispatcher, aMsg);
this._dispatchMessage(msg.type, dispatcher, aMsg, msg.msgID);
}, this);
} else {
// Since no handlers are registered, we need to notify the parent as if
// all the queued system messages have been handled (notice |handledCount:

View File

@ -9,7 +9,7 @@ interface nsIDOMWindow;
// Implemented by the contract id @mozilla.org/system-message-internal;1
[scriptable, uuid(6296a314-2abf-4cd0-9097-5e81ee6832e2)]
[scriptable, uuid(54c8e274-decb-4258-9a24-4ebfcbf3d00a)]
interface nsISystemMessagesInternal : nsISupports
{
/*
@ -22,8 +22,11 @@ interface nsISystemMessagesInternal : nsISupports
* @param manifestURI The webapp's manifest URI.
* @param extra Extra opaque information that will be passed around in the observer
* notification to open the page.
* returns a Promise
*/
void sendMessage(in DOMString type, in jsval message, in nsIURI pageURI, in nsIURI manifestURI, [optional] in jsval extra);
nsISupports sendMessage(in DOMString type, in jsval message,
in nsIURI pageURI, in nsIURI manifestURI,
[optional] in jsval extra);
/*
* Allow any internal user to broadcast a message of a given type.