Bug 960894 - 2.b/4: allow sharing WorkerMessenger between RadioInterface instances. r=hsinyi
authorVicamo Yang <vyang@mozilla.com>
Mon, 17 Feb 2014 19:35:03 +0800
changeset 169137 5dbab941f4e7b389f7dfeb3d0402a6a498645290
parent 169136 5ddf528d09dff99814c7d9131db2c741d94f1ecc
child 169138 504dda11bdf9438f072ac41998e8ddb3006074f4
push id26234
push userphilringnalda@gmail.com
push dateMon, 17 Feb 2014 23:16:21 +0000
treeherdermozilla-central@6b6450d3fbf0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsinyi
bugs960894
milestone30.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 960894 - 2.b/4: allow sharing WorkerMessenger between RadioInterface instances. r=hsinyi
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1556,17 +1556,20 @@ DataConnectionHandler.prototype = {
   },
 };
 
 function RadioInterfaceLayer() {
   let numIfaces = this.numRadioInterfaces;
   if (DEBUG) debug(numIfaces + " interfaces");
   this.radioInterfaces = [];
   for (let clientId = 0; clientId < numIfaces; clientId++) {
-    this.radioInterfaces.push(new RadioInterface(clientId));
+    let workerMessenger = new WorkerMessenger();
+    workerMessenger.init();
+
+    this.radioInterfaces.push(new RadioInterface(clientId, workerMessenger));
   }
 
   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
   gMessageManager.init(this);
   gRadioEnabledController.init(this);
   gDataConnectionManager.init(this);
 }
@@ -1631,30 +1634,27 @@ XPCOMUtils.defineLazyGetter(RadioInterfa
                             "numRadioInterfaces", function() {
   try {
     return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
   } catch(e) {}
 
   return 1;
 });
 
-function WorkerMessenger(radioInterface) {
+function WorkerMessenger() {
   // Initial owning attributes.
-  this.radioInterface = radioInterface;
+  this.radioInterfaces = [];
   this.tokenCallbackMap = {};
 
-  // Add a convenient alias to |radioInterface.debug()|.
-  this.debug = radioInterface.debug.bind(radioInterface);
-
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 }
 WorkerMessenger.prototype = {
-  radioInterface: null,
+  radioInterfaces: null,
   worker: null,
 
   // This gets incremented each time we send out a message.
   token: 1,
 
   // Maps tokens we send out with messages to the message callback.
   tokenCallbackMap: null,
 
@@ -1689,83 +1689,101 @@ WorkerMessenger.prototype = {
       options.cellBroadcastDisabled =
         Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
     } catch(e) {}
 
     try {
       options.clirMode = Services.prefs.getIntPref(kPrefClirModePreference);
     } catch(e) {}
 
-    if (DEBUG) this.debug("Starting RIL Worker");
-    let clientId = this.radioInterface.clientId;
-    options.clientId = clientId;
-    this.send("setInitialOptions", options);
-    gSystemWorkerManager.registerRilWorker(clientId, this.worker);
+    this.send(null, "setInitialOptions", options);
+  },
+
+  debug: function(aClientId, aMessage) {
+    // We use the same debug subject with RadioInterface's here.
+    dump("-*- RadioInterface[" + aClientId + "]: " + aMessage + "\n");
   },
 
   onerror: function(event) {
     if (DEBUG) {
-      this.debug("Got an error: " + event.filename + ":" +
+      this.debug("X", "Got an error: " + event.filename + ":" +
                  event.lineno + ": " + event.message + "\n");
     }
     event.preventDefault();
   },
 
   /**
    * Process the incoming message from the RIL worker.
    */
   onmessage: function(event) {
     let message = event.data;
+    let clientId = message.rilMessageClientId;
+    if (clientId === null) {
+      return;
+    }
+
     if (DEBUG) {
-      this.debug("Received message from worker: " + JSON.stringify(message));
+      this.debug(clientId, "Received message from worker: " + JSON.stringify(message));
     }
 
     let token = message.rilMessageToken;
     if (token == null) {
       // That's an unsolicited message.  Pass to RadioInterface directly.
-      this.radioInterface.handleUnsolicitedWorkerMessage(message);
+      let radioInterface = this.radioInterfaces[clientId];
+      radioInterface.handleUnsolicitedWorkerMessage(message);
       return;
     }
 
     let callback = this.tokenCallbackMap[message.rilMessageToken];
     if (!callback) {
-      if (DEBUG) this.debug("Ignore orphan token: " + message.rilMessageToken);
+      if (DEBUG) this.debug(clientId, "Ignore orphan token: " + message.rilMessageToken);
       return;
     }
 
     let keep = false;
     try {
       keep = callback(message);
     } catch(e) {
-      if (DEBUG) this.debug("callback throws an exception: " + e);
+      if (DEBUG) this.debug(clientId, "callback throws an exception: " + e);
     }
 
     if (!keep) {
       delete this.tokenCallbackMap[message.rilMessageToken];
     }
   },
 
+  registerClient: function(aClientId, aRadioInterface) {
+    if (DEBUG) this.debug(aClientId, "Starting RIL Worker");
+
+    // Keep a reference so that we can dispatch unsolicited messages to it.
+    this.radioInterfaces[aClientId] = aRadioInterface;
+
+    this.send(null, "registerClient", { clientId: aClientId });
+    gSystemWorkerManager.registerRilWorker(aClientId, this.worker);
+  },
+
   /**
    * Send arbitrary message to worker.
    *
    * @param rilMessageType
    *        A text message type.
    * @param message [optional]
    *        An optional message object to send.
    * @param callback [optional]
    *        An optional callback function which is called when worker replies
    *        with an message containing a "rilMessageToken" attribute of the
    *        same value we passed.  This callback function accepts only one
    *        parameter -- the reply from worker.  It also returns a boolean
    *        value true to keep current token-callback mapping and wait for
    *        another worker reply, or false to remove the mapping.
    */
-  send: function(rilMessageType, message, callback) {
+  send: function(clientId, rilMessageType, message, callback) {
     message = message || {};
 
+    message.rilMessageClientId = clientId;
     message.rilMessageToken = this.token;
     this.token++;
 
     if (callback) {
       // Only create the map if callback is provided.  For sending a request
       // and intentionally leaving the callback undefined, that reply will
       // be dropped in |this.onmessage| because of that orphan token.
       //
@@ -1786,32 +1804,36 @@ WorkerMessenger.prototype = {
    *        A message object from ppmm.
    * @param rilMessageType
    *        A text string for worker message type.
    * @param ipcType [optinal]
    *        A text string for ipc message type. "msg.name" if omitted.
    *
    * @TODO: Bug 815526 - deprecate RILContentHelper.
    */
-  sendWithIPCMessage: function(msg, rilMessageType, ipcType) {
-    this.send(rilMessageType, msg.json.data, (function(reply) {
+  sendWithIPCMessage: function(clientId, msg, rilMessageType, ipcType) {
+    this.send(clientId, rilMessageType, msg.json.data, (function(reply) {
       ipcType = ipcType || msg.name;
       msg.target.sendAsyncMessage(ipcType, {
-        clientId: this.radioInterface.clientId,
+        clientId: clientId,
         data: reply
       });
       return false;
     }).bind(this));
   }
 };
 
-function RadioInterface(aClientId) {
+function RadioInterface(aClientId, aWorkerMessenger) {
   this.clientId = aClientId;
-  this.workerMessenger = new WorkerMessenger(this);
-  this.workerMessenger.init();
+  this.workerMessenger = {
+    send: aWorkerMessenger.send.bind(aWorkerMessenger, aClientId),
+    sendWithIPCMessage:
+      aWorkerMessenger.sendWithIPCMessage.bind(aWorkerMessenger, aClientId),
+  };
+  aWorkerMessenger.registerClient(aClientId, this);
 
   this.supportedNetworkTypes = this.getSupportedNetworkTypes();
 
   this.rilContext = {
     radioState:     RIL.GECKO_RADIOSTATE_UNAVAILABLE,
     detailedRadioState: null,
     cardState:      RIL.GECKO_CARDSTATE_UNKNOWN,
     networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
@@ -1894,17 +1916,17 @@ RadioInterface.prototype = {
   classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACE_CID,
                                     classDescription: "RadioInterface",
                                     interfaces: [Ci.nsIRadioInterface]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterface,
                                          Ci.nsIObserver,
                                          Ci.nsISettingsServiceCallback]),
 
-  // A private WorkerMessenger instance.
+  // A private wrapped WorkerMessenger instance.
   workerMessenger: null,
 
   debug: function(s) {
     dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n");
   },
 
   shutdown: function() {
     // Release the CPU wake lock for handling the received SMS.
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -4940,16 +4940,17 @@ let RIL = {
     cmdDetails.options = StkCommandParamsFactory.createParam(cmdDetails, ctlvs);
     RIL.sendChromeMessage(cmdDetails);
   },
 
   /**
    * Send messages to the main thread.
    */
   sendChromeMessage: function(message) {
+    message.rilMessageClientId = CLIENT_ID;
     postMessage(message);
   },
 
   /**
    * Handle incoming requests from the RIL. We find the method that
    * corresponds to the request type. Incidentally, the request type
    * _is_ the method name, so that's easy.
    */
@@ -4959,29 +4960,32 @@ let RIL = {
     if (typeof method == "function") {
       if (DEBUG) debug("Handling parcel as " + method.name);
       method.call(this, length, options);
     }
   },
 
   setInitialOptions: function(options) {
     DEBUG = DEBUG_WORKER || options.debug;
-    CLIENT_ID = options.clientId;
     this.cellBroadcastDisabled = options.cellBroadcastDisabled;
     this.clirMode = options.clirMode;
     RIL_EMERGENCY_NUMBERS = options.rilEmergencyNumbers;
     let quirks = options.quirks;
     RILQUIRKS_CALLSTATE_EXTRA_UINT32 = quirks.callstateExtraUint32;
     RILQUIRKS_V5_LEGACY = quirks.v5Legacy;
     RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall;
     RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields;
     RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall;
     RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount;
     RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload;
     RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand;
+  },
+
+  registerClient: function(aOptions) {
+    CLIENT_ID = aOptions.clientId;
   }
 };
 
 RIL.initRILState();
 
 RIL[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS(length, options) {
   if (options.rilRequestError) {
     return;