Bug 1454038 - 3. Reject sendRequestForResult promise on finalize; r?esawin draft
authorJim Chen <nchen@mozilla.com>
Tue, 17 Apr 2018 16:13:39 -0400
changeset 783836 a519d55d046dc638525e5ca15732eb20b115803f
parent 783835 d92cf5539f8bcfa4c811d52e65b44595c7fa6567
push id106800
push userbmo:nchen@mozilla.com
push dateTue, 17 Apr 2018 20:15:42 +0000
reviewersesawin
bugs1454038
milestone61.0a1
Bug 1454038 - 3. Reject sendRequestForResult promise on finalize; r?esawin When a sendRequestForResult event callback is finalized, automatically reject the promise (if it has not been resolved yet). This means if the callback is never called, or if the communication link is disrupted, we will end up with a rejected promise rather than a forever-pending promise. MozReview-Commit-ID: A1w19vwFxuT
mobile/android/modules/geckoview/Messaging.jsm
--- a/mobile/android/modules/geckoview/Messaging.jsm
+++ b/mobile/android/modules/geckoview/Messaging.jsm
@@ -107,20 +107,31 @@ DispatcherDelegate.prototype = {
    * @param aMsg Message to send; must be an object with a "type" property
    * @return A Promise resolving to the response
    */
   sendRequestForResult: function(aMsg) {
     return new Promise((resolve, reject) => {
       const type = aMsg.type;
       aMsg.type = undefined;
 
-      this.dispatch(type, aMsg, {
-        onSuccess: resolve,
-        onError: reject,
-      });
+      // Manually release the resolve/reject functions after one callback is
+      // received, so the JS GC is not tied up with the Java GC.
+      const onCallback = (callback, ...args) => {
+        if (callback) {
+          callback(...args);
+        }
+        resolve = undefined;
+        reject = undefined;
+      };
+      const callback = {
+        onSuccess: result => onCallback(resolve, result),
+        onError: error => onCallback(reject, error),
+        onFinalize: _ => onCallback(reject),
+      };
+      this.dispatch(type, aMsg, callback, callback);
     });
   },
 
   finalize: function() {
     if (!this._replies) {
       return;
     }
     this._replies.forEach(reply => {