Bug 1449821 - 4. Use one child message listener per EventDispatcher; r=esawin
authorJim Chen <nchen@mozilla.com>
Thu, 05 Apr 2018 18:50:11 -0400
changeset 457017 7ddea90ba7dba38a8ae685765862dcebdf7037fc
parent 457016 a6ccb53865ed0adf193a93f600aa2173b3df875a
child 457018 cb8f70b3944abf4f8e97d092dde7f5417b7300a2
push id153
push userfmarier@mozilla.com
push dateTue, 10 Apr 2018 02:28:40 +0000
reviewersesawin
bugs1449821
milestone61.0a1
Bug 1449821 - 4. Use one child message listener per EventDispatcher; r=esawin Instead of registering a new message listener for every event, register a single listener for each EventDispatcher to improve performance. MozReview-Commit-ID: Lg7eR29uESo
mobile/android/modules/geckoview/Messaging.jsm
--- a/mobile/android/modules/geckoview/Messaging.jsm
+++ b/mobile/android/modules/geckoview/Messaging.jsm
@@ -13,16 +13,23 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIUUIDGenerator");
 
 const IS_PARENT_PROCESS = (Services.appinfo.processType ==
                            Services.appinfo.PROCESS_TYPE_DEFAULT);
 
 function DispatcherDelegate(aDispatcher, aMessageManager) {
   this._dispatcher = aDispatcher;
   this._messageManager = aMessageManager;
+
+  if (!aDispatcher) {
+    // Child process.
+    this._replies = new Map();
+    (aMessageManager || Services.cpmm).addMessageListener(
+        "GeckoView:MessagingReply", this);
+  }
 }
 
 DispatcherDelegate.prototype = {
   /**
    * Register a listener to be notified of event(s).
    *
    * @param aListener Target listener implementing nsIAndroidEventListener.
    * @param aEvents   String or array of strings of events to listen to.
@@ -66,32 +73,22 @@ DispatcherDelegate.prototype = {
     let mm = this._messageManager || Services.cpmm;
     let forwardData = {
       global: !this._messageManager,
       event: aEvent,
       data: aData,
     };
 
     if (aCallback) {
-      forwardData.uuid = UUIDGen.generateUUID().toString();
-      mm.addMessageListener("GeckoView:MessagingReply", function listener(msg) {
-        if (msg.data.uuid !== forwardData.uuid) {
-          return;
-        }
-        if (msg.data.type === "success") {
-          aCallback.onSuccess(msg.data.response);
-        } else if (msg.data.type === "error") {
-          aCallback.onError(msg.data.response);
-        } else if (msg.data.type === "finalize") {
-          aFinalizer && aFinalizer.onFinalize();
-          mm.removeMessageListener(msg.name, listener);
-        } else {
-          throw new Error("invalid reply type");
-        }
+      const uuid = UUIDGen.generateUUID().toString();
+      this._replies.set(uuid, {
+        callback: aCallback,
+        finalizer: aFinalizer,
       });
+      forwardData.uuid = uuid;
     }
 
     mm.sendAsyncMessage("GeckoView:Messaging", forwardData);
   },
 
   /**
    * Sends a request to Java.
    *
@@ -116,16 +113,39 @@ DispatcherDelegate.prototype = {
       aMsg.type = undefined;
 
       this.dispatch(type, aMsg, {
         onSuccess: resolve,
         onError: reject,
       });
     });
   },
+
+  receiveMessage: function(aMsg) {
+    const {uuid, type} = aMsg.data;
+    const reply = this._replies.get(uuid);
+    if (!reply) {
+      return;
+    }
+
+    if (type === "success") {
+      reply.callback.onSuccess(aMsg.data.response);
+    } else if (type === "error") {
+      reply.callback.onError(aMsg.data.response);
+    } else if (type === "finalize") {
+      if (typeof reply.finalizer === "function") {
+        reply.finalizer();
+      } else if (reply.finalizer) {
+        reply.finalizer.onFinalize();
+      }
+      this._replies.delete(uuid);
+    } else {
+      throw new Error("invalid reply type");
+    }
+  },
 };
 
 var EventDispatcher = {
   instance: new DispatcherDelegate(IS_PARENT_PROCESS ? Services.androidBridge : undefined),
 
   /**
    * Return an EventDispatcher instance for a chrome DOM window. In a content
    * process, return a proxy through the message manager that automatically