Bug 907585 [2/3]: Re-implement message listener registration. r=yoshi
☠☠ backed out by dc4758d44b11 ☠ ☠
authorVicamo Yang <vyang@mozilla.com>
Fri, 06 Sep 2013 16:11:46 +0800
changeset 158771 9039460e09c58ce94e85865eca87c8cb3699700d
parent 158770 9464e393a501faa53f29ccf77f35cb03305ae75f
child 158772 8020b30136185269fd2ba61b3dc16f060a549c5a
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoshi
bugs907585
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 907585 [2/3]: Re-implement message listener registration. r=yoshi
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/RilMessageManager.jsm
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -74,17 +74,16 @@ const RADIO_POWER_OFF_TIMEOUT = 30000;
 
 const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
   "RIL:GetRilContext",
   "RIL:GetAvailableNetworks",
   "RIL:SelectNetwork",
   "RIL:SelectNetworkAuto",
   "RIL:SendMMI",
   "RIL:CancelMMI",
-  "RIL:RegisterMobileConnectionMsg",
   "RIL:SetCallForwardingOption",
   "RIL:GetCallForwardingOption",
   "RIL:SetCallBarringOption",
   "RIL:GetCallBarringOption",
   "RIL:ChangeCallBarringPassword",
   "RIL:SetCallWaitingOption",
   "RIL:GetCallWaitingOption",
   "RIL:SetCallingLineIdRestriction",
@@ -104,29 +103,23 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
   "RIL:GetCardLockState",
   "RIL:UnlockCardLock",
   "RIL:SetCardLock",
   "RIL:GetCardLockRetryCount",
   "RIL:IccOpenChannel",
   "RIL:IccExchangeAPDU",
   "RIL:IccCloseChannel",
   "RIL:ReadIccContacts",
-  "RIL:UpdateIccContact",
-  "RIL:RegisterIccMsg"
+  "RIL:UpdateIccContact"
 ];
 
 const RIL_IPC_VOICEMAIL_MSG_NAMES = [
-  "RIL:RegisterVoicemailMsg",
   "RIL:GetVoicemailInfo"
 ];
 
-const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
-  "RIL:RegisterCellBroadcastMsg"
-];
-
 XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
                                    "@mozilla.org/power/powermanagerservice;1",
                                    "nsIPowerManagerService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
                                    "@mozilla.org/mobilemessage/mobilemessageservice;1",
                                    "nsIMobileMessageService");
 
@@ -176,17 +169,26 @@ XPCOMUtils.defineLazyGetter(this, "Phone
 
 XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
   let ns = {};
   Cu.import("resource://gre/modules/RilMessageManager.jsm", ns);
   return ns.RilMessageManager;
 });
 
 function RadioInterfaceLayer() {
-  gMessageManager.init(this);
+  let callback = this._receiveMessage.bind(this);
+  gMessageManager.registerMessageListeners("icc",
+                                           RIL_IPC_ICCMANAGER_MSG_NAMES,
+                                           callback);
+  gMessageManager.registerMessageListeners("mobileconnection",
+                                           RIL_IPC_MOBILECONNECTION_MSG_NAMES,
+                                           callback);
+  gMessageManager.registerMessageListeners("voicemail",
+                                           RIL_IPC_VOICEMAIL_MSG_NAMES,
+                                           callback);
 
   let options = {
     debug: debugPref,
     cellBroadcastDisabled: false,
     clirMode: RIL.CLIR_DEFAULT
   };
 
   try {
@@ -211,16 +213,27 @@ RadioInterfaceLayer.prototype = {
   classID:   RADIOINTERFACELAYER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
                                     classDescription: "RadioInterfaceLayer",
                                     interfaces: [Ci.nsIRadioInterfaceLayer]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
                                          Ci.nsIObserver]),
 
+  _receiveMessage: function _receiveMessage(topic, msg) {
+    let clientId = msg.json.clientId || 0;
+    let radioInterface = this.getRadioInterface(clientId);
+    if (!radioInterface) {
+      if (DEBUG) debug("No such radio interface: " + clientId);
+      return null;
+    }
+
+    return radioInterface.receiveMessage(msg);
+  },
+
   /**
    * nsIObserver interface methods.
    */
 
   observe: function observe(subject, topic, data) {
     // Nothing to do now. Just for profile-after-change.
   },
 
--- a/dom/system/gonk/RilMessageManager.jsm
+++ b/dom/system/gonk/RilMessageManager.jsm
@@ -22,84 +22,75 @@ let DEBUG;
 function debug(s) {
   dump("RilMessageManager: " + s + "\n");
 }
 
 this.RilMessageManager = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
                                          Ci.nsIObserver]),
 
-  ril: null,
+  topicRegistrationNames: {
+    cellbroadcast:    "RIL:RegisterCellBroadcastMsg",
+    icc:              "RIL:RegisterIccMsg",
+    mobileconnection: "RIL:RegisterMobileConnectionMsg",
+    voicemail:        "RIL:RegisterVoicemailMsg",
+  },
+
+  /**
+   * this.callbacksByName[< A string message name>] = {
+   *   topic:    <A string topic>,
+   *   callback: <A callback that accepts two parameters -- topic and msg>,
+   * }
+   */
+  callbacksByName: {},
 
   // Manage message targets in terms of topic. Only the authorized and
   // registered contents can receive related messages.
   targetsByTopic: {},
   topics: [],
 
   targetMessageQueue: [],
   ready: false,
 
-  init: function init(ril) {
-    this.ril = ril;
-
+  _init: function _init() {
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
-    this._registerMessageListeners();
+
+    ppmm.addMessageListener("child-process-shutdown", this);
+
+    let callback = this._registerMessageTarget.bind(this);
+    for (let topic in this.topicRegistrationNames) {
+      let name = this.topicRegistrationNames[topic];
+      this.registerMessageListeners(topic, [name], callback);
+    }
   },
 
   _shutdown: function _shutdown() {
-    this.ril = null;
-
     Services.obs.removeObserver(this, "xpcom-shutdown");
-    this._unregisterMessageListeners();
-  },
 
-  _registerMessageListeners: function _registerMessageListeners() {
-    ppmm.addMessageListener("child-process-shutdown", this);
-    for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
-      ppmm.addMessageListener(msgname, this);
-    }
-    for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
-      ppmm.addMessageListener(msgName, this);
-    }
-    for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
-      ppmm.addMessageListener(msgname, this);
+    for (let name in this.callbacksByName) {
+      ppmm.removeMessageListener(name, this);
     }
-    for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
-      ppmm.addMessageListener(msgname, this);
-    }
-  },
+    this.callbacksByName = null;
 
-  _unregisterMessageListeners: function _unregisterMessageListeners() {
     ppmm.removeMessageListener("child-process-shutdown", this);
-    for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
-      ppmm.removeMessageListener(msgname, this);
-    }
-    for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
-      ppmm.removeMessageListener(msgName, this);
-    }
-    for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
-      ppmm.removeMessageListener(msgname, this);
-    }
-    for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
-      ppmm.removeMessageListener(msgname, this);
-    }
     ppmm = null;
   },
 
-  _registerMessageTarget: function _registerMessageTarget(topic, target) {
+  _registerMessageTarget: function _registerMessageTarget(topic, msg) {
     let targets = this.targetsByTopic[topic];
     if (!targets) {
       targets = this.targetsByTopic[topic] = [];
       let list = this.topics;
       if (list.indexOf(topic) == -1) {
         list.push(topic);
       }
     }
 
+    let target = msg.target;
     if (targets.indexOf(target) != -1) {
       if (DEBUG) debug("Already registered this target!");
       return;
     }
 
     targets.push(target);
     if (DEBUG) debug("Registered " + topic + " target: " + target);
   },
@@ -183,76 +174,31 @@ this.RilMessageManager = {
     if (msg.name == "child-process-shutdown") {
       // By the time we receive child-process-shutdown, the child process has
       // already forgotten its permissions so we need to unregister the target
       // for every permission.
       this._unregisterMessageTarget(null, msg.target);
       return;
     }
 
-    if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
-      if (!msg.target.assertPermission("mobileconnection")) {
-        if (DEBUG) {
-          debug("MobileConnection message " + msg.name +
-                " from a content process with no 'mobileconnection' privileges.");
-        }
-        return null;
-      }
-    } else if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) {
-      if (!msg.target.assertPermission("mobileconnection")) {
-        if (DEBUG) {
-          debug("IccManager message " + msg.name +
-                " from a content process with no 'mobileconnection' privileges.");
-        }
-        return null;
-      }
-    } else if (RIL_IPC_VOICEMAIL_MSG_NAMES.indexOf(msg.name) != -1) {
-      if (!msg.target.assertPermission("voicemail")) {
-        if (DEBUG) {
-          debug("Voicemail message " + msg.name +
-                " from a content process with no 'voicemail' privileges.");
-        }
-        return null;
-      }
-    } else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
-      if (!msg.target.assertPermission("cellbroadcast")) {
-        if (DEBUG) {
-          debug("Cell Broadcast message " + msg.name +
-                " from a content process with no 'cellbroadcast' privileges.");
-        }
-        return null;
-      }
-    } else {
+    let entry = this.callbacksByName[msg.name];
+    if (!entry) {
       if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
       return null;
     }
 
-    switch (msg.name) {
-      case "RIL:RegisterMobileConnectionMsg":
-        this._registerMessageTarget("mobileconnection", msg.target);
-        return;
-      case "RIL:RegisterIccMsg":
-        this._registerMessageTarget("icc", msg.target);
-        return;
-      case "RIL:RegisterVoicemailMsg":
-        this._registerMessageTarget("voicemail", msg.target);
-        return;
-      case "RIL:RegisterCellBroadcastMsg":
-        this._registerMessageTarget("cellbroadcast", msg.target);
-        return;
-    }
-
-    let clientId = msg.json.clientId || 0;
-    let radioInterface = this.ril.getRadioInterface(clientId);
-    if (!radioInterface) {
-      if (DEBUG) debug("No such radio interface: " + clientId);
+    if (entry.topic && !msg.target.assertPermission(entry.topic)) {
+      if (DEBUG) {
+        debug("Message " + msg.name + " from a content process with no '" +
+              entry.topic + "' privileges.");
+      }
       return null;
     }
 
-    return radioInterface.receiveMessage(msg);
+    return entry.callback(entry.topic, msg);
   },
 
   /**
    * nsIObserver interface methods.
    */
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
@@ -265,16 +211,59 @@ this.RilMessageManager = {
         break;
     }
   },
 
   /**
    * Public methods.
    */
 
+  /**
+   * @param topic
+   *        A string for the topic of the registrating names. Also the
+   *        permission to listen messages of these names.
+   * @param names
+   *        An array of string message names to listen.
+   * @param callback
+   *        A callback that accepts two parameters -- topic and msg.
+   */
+  registerMessageListeners: function registerMessageListeners(topic, names,
+                                                              callback) {
+    for (let name of names) {
+      if (this.callbacksByName[name]) {
+        if (DEBUG) {
+          debug("Message name '" + name + "' was already registered. Ignored.");
+        }
+        continue;
+      }
+
+      this.callbacksByName[name] = { topic: topic, callback: callback };
+      ppmm.addMessageListener(name, this);
+    }
+  },
+
+  /**
+   * Remove all listening names with specified callback.
+   *
+   * @param callback
+   *        The callback previously registered for messages.
+   */
+  unregisterMessageListeners: function unregisterMessageListeners(callback) {
+    let remains = {};
+    for (let name in this.callbacksByName) {
+      let entry = this.callbacksByName[name];
+      if (entry.callback != callback) {
+        remains[name] = entry;
+      } else {
+        ppmm.removeMessageListener(name, this);
+      }
+    }
+    this.callbacksByName = remains;
+  },
+
   sendMobileConnectionMessage: function sendMobileConnectionMessage(name, clientId, data) {
     this._sendTargetMessage("mobileconnection", name, {
       clientId: clientId,
       data: data
     });
   },
 
   sendVoicemailMessage: function sendVoicemailMessage(name, clientId, data) {
@@ -294,9 +283,11 @@ this.RilMessageManager = {
   sendIccMessage: function sendIccMessage(name, clientId, data) {
     this._sendTargetMessage("icc", name, {
       clientId: clientId,
       data: data
     });
   }
 };
 
+RilMessageManager._init();
+
 this.EXPORTED_SYMBOLS = ["RilMessageManager"];