diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 8ece24377d6..e4fb44c49b9 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -1847,6 +1847,33 @@ Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv) return result; } +void +Navigator::MozSetMessageHandlerPromise(Promise& aPromise, + ErrorResult& aRv) +{ + // The WebIDL binding is responsible for the pref check here. + aRv = EnsureMessagesManager(); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + bool result = false; + aRv = mMessagesManager->MozIsHandlingMessage(&result); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + if (!result) { + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return; + } + + aRv = mMessagesManager->MozSetMessageHandlerPromise(&aPromise); + if (NS_WARN_IF(aRv.Failed())) { + return; + } +} + void Navigator::MozSetMessageHandler(const nsAString& aType, systemMessageCallback* aCallback, diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 3852e49c901..7d7daff15ad 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -235,6 +235,8 @@ public: systemMessageCallback* aCallback, ErrorResult& aRv); bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv); + void MozSetMessageHandlerPromise(Promise& aPromise, ErrorResult& aRv); + #ifdef MOZ_B2G already_AddRefed GetMobileIdAssertion(const MobileIdOptions& options, ErrorResult& aRv); diff --git a/dom/messages/SystemMessageManager.js b/dom/messages/SystemMessageManager.js index 538b9e7fa49..b9740a52d14 100644 --- a/dom/messages/SystemMessageManager.js +++ b/dom/messages/SystemMessageManager.js @@ -42,6 +42,10 @@ function SystemMessageManager() { // Flag to specify if this process has already registered the manifest URL. this._registerManifestURLReady = false; + // Used to know if the promise has to be accepted or not. + this._isHandling = false; + this._promise = null; + // Flag to determine this process is a parent or child process. let appInfo = Cc["@mozilla.org/xre/app-info;1"]; this._isParentProcess = @@ -71,6 +75,7 @@ SystemMessageManager.prototype = { } aDispatcher.isHandling = true; + this._isHandling = true; // We get a json blob, but in some cases we want another kind of object // to be dispatched. To do so, we check if we have a valid contract ID of @@ -94,15 +99,29 @@ SystemMessageManager.prototype = { .handleMessage(wrapped ? aMessage : Cu.cloneInto(aMessage, this._window)); - // 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:HandleMessageDone", - { type: aType, - manifestURL: this._manifestURL, - pageURL: this._pageURL, - msgID: aMessageID }); - aDispatcher.isHandling = false; + this._isHandling = false; + + let self = this; + function sendResponse() { + // 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:HandleMessageDone", + { type: aType, + manifestURL: self._manifestURL, + pageURL: self._pageURL, + msgID: aMessageID }); + } + + if (!this._promise) { + debug("No promise set, sending the response immediately"); + sendResponse(); + } else { + debug("Using the promise to postpone the response."); + this._promise.then(sendResponse, sendResponse); + this._promise = null; + } if (aDispatcher.messages.length > 0) { let msg = aDispatcher.messages.shift(); @@ -171,9 +190,25 @@ SystemMessageManager.prototype = { manifestURL: this._manifestURL })[0]; }, + mozIsHandlingMessage: function() { + debug("is handling message: " + this._isHandling); + return this._isHandling; + }, + + mozSetMessageHandlerPromise: function(aPromise) { + debug("setting a promise"); + + if (!this._isHandling) { + throw "Not in a handleMessage method"; + } + + this._promise = aPromise; + }, + uninit: function() { this._dispatchers = null; this._pendings = null; + this._promise = null; if (this._isParentProcess) { Services.obs.removeObserver(this, kSystemMessageInternalReady); diff --git a/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl b/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl index 855cfb0c8c7..4fc156c0e9d 100644 --- a/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl +++ b/dom/messages/interfaces/nsIDOMNavigatorSystemMessages.idl @@ -10,10 +10,15 @@ interface nsIDOMSystemMessageCallback : nsISupports void handleMessage(in jsval message); }; -[scriptable, uuid(091e90dd-0e8b-463d-8cdc-9225d3a6ff90)] +[scriptable, uuid(d04d3c11-26aa-46eb-a981-353af101f9cf)] interface nsIDOMNavigatorSystemMessages : nsISupports { void mozSetMessageHandler(in DOMString type, in nsIDOMSystemMessageCallback callback); boolean mozHasPendingMessage(in DOMString type); + + // the parameter is a promise object. + void mozSetMessageHandlerPromise(in nsISupports promise); + + bool mozIsHandlingMessage(); }; diff --git a/dom/requestsync/RequestSyncService.jsm b/dom/requestsync/RequestSyncService.jsm index 03df16c7140..dbd8d3422d1 100644 --- a/dom/requestsync/RequestSyncService.jsm +++ b/dom/requestsync/RequestSyncService.jsm @@ -587,10 +587,16 @@ this.RequestSyncService = { timer = null; } + let timeout = RSYNC_OPERATION_TIMEOUT; + try { + let tmp = Services.prefs.getIntPref("dom.requestSync.maxTaskTimeout"); + timeout = tmp; + } catch(e) {} + timer.initWithCallback(function() { debug("Task is taking too much, let's ignore the promise."); taskCompleted(); - }, RSYNC_OPERATION_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT); + }, timeout, Ci.nsITimer.TYPE_ONE_SHOT); // Sending the message. let promise = diff --git a/dom/requestsync/tests/mochitest.ini b/dom/requestsync/tests/mochitest.ini index b1071e0e76c..a5fee3b1064 100644 --- a/dom/requestsync/tests/mochitest.ini +++ b/dom/requestsync/tests/mochitest.ini @@ -14,3 +14,6 @@ support-files = run-if = buildapp != 'b2g' [test_wakeUp.html] run-if = buildapp == 'b2g' && toolkit == 'gonk' +[test_promise.html] +[test_promise_app.html] +run-if = buildapp == 'b2g' && toolkit == 'gonk' diff --git a/dom/requestsync/tests/test_basic_app.html b/dom/requestsync/tests/test_basic_app.html index 21437ae3eb2..bb5baeb4f39 100644 --- a/dom/requestsync/tests/test_basic_app.html +++ b/dom/requestsync/tests/test_basic_app.html @@ -72,7 +72,7 @@ SpecialPowers.pushPermissions( [{ "type": "browser", "allow": 1, "context": document }, { "type": "embed-apps", "allow": 1, "context": document }, - {"type": "requestsync-manager", "allow": 1, "context": document }, + { "type": "requestsync-manager", "allow": 1, "context": document }, { "type": "webapps-manage", "allow": 1, "context": document }], runTests); }, diff --git a/dom/requestsync/tests/test_promise.html b/dom/requestsync/tests/test_promise.html new file mode 100644 index 00000000000..8277eadaa6d --- /dev/null +++ b/dom/requestsync/tests/test_promise.html @@ -0,0 +1,56 @@ + + + + + Test for requestSync - promise + + + + + +
+ + + diff --git a/dom/requestsync/tests/test_promise_app.html b/dom/requestsync/tests/test_promise_app.html new file mode 100644 index 00000000000..9039c8e0fba --- /dev/null +++ b/dom/requestsync/tests/test_promise_app.html @@ -0,0 +1,138 @@ + + + + + Test for requestSync - promise + + + + + +
+ + + diff --git a/dom/requestsync/tests/test_wakeUp.html b/dom/requestsync/tests/test_wakeUp.html index f19c4f3a150..14d7ec6040c 100644 --- a/dom/requestsync/tests/test_wakeUp.html +++ b/dom/requestsync/tests/test_wakeUp.html @@ -84,6 +84,22 @@ }, genericError); } + function test_unregister_oneShot() { + navigator.sync.unregister('oneShot').then( + function() { + ok(true, "navigator.sync.unregister() oneShot done"); + runTests(); + }, genericError); + } + + function test_unregister_multiShots() { + navigator.sync.unregister('multiShots').then( + function() { + ok(true, "navigator.sync.unregister() multiShots done"); + runTests(); + }, genericError); + } + function test_wait() { // nothing to do here. } @@ -113,6 +129,9 @@ test_register_multiShots, test_wait, + + test_unregister_oneShot, + test_unregister_multiShots, ]; function runTests() { diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 653facf8237..64b67d5c434 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -285,6 +285,12 @@ partial interface Navigator { void mozSetMessageHandler (DOMString type, systemMessageCallback? callback); [Throws, Pref="dom.sysmsg.enabled"] boolean mozHasPendingMessage (DOMString type); + + // This method can be called only from the systeMessageCallback function and + // it allows the page to set a promise to keep alive the app until the + // current operation is not fully completed. + [Throws, Pref="dom.sysmsg.enabled"] + void mozSetMessageHandlerPromise (Promise promise); }; #ifdef MOZ_B2G_RIL