Bug 777202 - RadioInterfaceLayer broadcasts request responses to all content processes. r=philikon
authorHsin-Yi Tsai <htsai@mozilla.com>
Fri, 17 Aug 2012 11:46:34 +0800
changeset 102624 e1cd9fb39dd77c26cc99b20d488683632a802074
parent 102623 c8f9da21bc8891413d2e853773b2102af6c2ede6
child 102625 f5f29adc6d30246a6fa4e35bac207de1e9a827e4
child 102630 c22f375fec38613d004e85c57a6bea49180674c3
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersphilikon
bugs777202
milestone17.0a1
Bug 777202 - RadioInterfaceLayer broadcasts request responses to all content processes. r=philikon
dom/system/gonk/RILContentHelper.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -63,16 +63,20 @@ const kVoiceChangedTopic     = "mobile-c
 const kDataChangedTopic      = "mobile-connection-data-changed";
 const kCardStateChangedTopic = "mobile-connection-cardstate-changed";
 const kUssdReceivedTopic     = "mobile-connection-ussd-received";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIFrameMessageManager");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
 function MobileConnectionInfo() {}
 MobileConnectionInfo.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileConnectionInfo]),
   classID:        MOBILECONNECTIONINFO_CID,
   classInfo:      XPCOMUtils.generateCI({
     classID:          MOBILECONNECTIONINFO_CID,
     classDescription: "MobileConnectionInfo",
     flags:            Ci.nsIClassInfo.DOM_OBJECT,
@@ -235,17 +239,17 @@ RILContentHelper.prototype = {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
 
     let request = Services.DOMRequest.createRequest(window);
     let requestId = this.getRequestId(request);
 
-    cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", requestId);
+    cpmm.sendAsyncMessage("RIL:GetAvailableNetworks", {requestId: requestId});
     return request;
   },
 
   selectNetwork: function selectNetwork(window, network) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
@@ -308,17 +312,17 @@ RILContentHelper.prototype = {
     if (this.networkSelectionMode == RIL.GECKO_NETWORK_SELECTION_AUTOMATIC) {
       // Already using automatic selection mode, so schedule
       // onsuccess to be be fired on the next tick
       this.dispatchFireRequestSuccess(requestId, null);
       return request;
     }
 
     this._selectingNetwork = "automatic";
-    cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", requestId);
+    cpmm.sendAsyncMessage("RIL:SelectNetworkAuto", {requestId: requestId});
     return request;
   },
 
   getCardLock: function getCardLock(window, lockType) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
@@ -422,17 +426,20 @@ RILContentHelper.prototype = {
   },
 
   unregisterVoicemailCallback: function unregisteVoicemailCallback(callback) {
     this.unregisterCallback("_voicemailCallbacks", callback);
   },
 
   enumerateCalls: function enumerateCalls(callback) {
     debug("Requesting enumeration of calls for callback: " + callback);
-    cpmm.sendAsyncMessage("RIL:EnumerateCalls");
+    // We need 'requestId' to meet the 'RILContentHelper <--> RadioInterfaceLayer'
+    // protocol.
+    let requestId = this._getRandomId();
+    cpmm.sendAsyncMessage("RIL:EnumerateCalls", {requestId: requestId});
     if (!this._enumerationTelephonyCallbacks) {
       this._enumerationTelephonyCallbacks = [];
     }
     this._enumerationTelephonyCallbacks.push(callback);
   },
 
   startTone: function startTone(dtmfChar) {
     debug("Sending Tone for " + dtmfChar);
@@ -558,17 +565,17 @@ RILContentHelper.prototype = {
         this.updateConnectionInfo(msg.json, this.voiceConnectionInfo);
         Services.obs.notifyObservers(null, kVoiceChangedTopic, null);
         break;
       case "RIL:DataInfoChanged":
         this.updateConnectionInfo(msg.json, this.dataConnectionInfo);
         Services.obs.notifyObservers(null, kDataChangedTopic, null);
         break;
       case "RIL:EnumerateCalls":
-        this.handleEnumerateCalls(msg.json);
+        this.handleEnumerateCalls(msg.json.calls);
         break;
       case "RIL:GetAvailableNetworks":
         this.handleGetAvailableNetworks(msg.json);
         break;
       case "RIL:NetworkSelectionModeChanged":
         this.networkSelectionMode = msg.json.mode;
         break;
       case "RIL:SelectNetwork":
@@ -717,16 +724,20 @@ RILContentHelper.prototype = {
 
     if (changed) {
       this._deliverCallback("_voicemailCallbacks",
                             "voicemailNotification",
                             [this.voicemailStatus]);
     }
   },
 
+  _getRandomId: function _getRandomId() {
+    return gUUIDGenerator.generateUUID().toString();
+  },
+
   _deliverCallback: function _deliverCallback(callbackType, name, args) {
     let thisCallbacks = this[callbackType];
     if (!thisCallbacks) {
       return;
     }
 
     let callbacks = thisCallbacks.slice();
     for each (let callback in callbacks) {
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -189,16 +189,18 @@ function RadioInterfaceLayer() {
   this._dataCallSettingsToRead = ["ril.data.enabled",
                                   "ril.data.roaming_enabled",
                                   "ril.data.apn",
                                   "ril.data.user",
                                   "ril.data.passwd",
                                   "ril.data.httpProxyHost",
                                   "ril.data.httpProxyPort"];
 
+  this._messageManagerByRequest = {};
+
   for each (let msgname in RIL_IPC_MSG_NAMES) {
     ppmm.addMessageListener(msgname, this);
   }
   Services.obs.addObserver(this, "xpcom-shutdown", false);
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
 
   this._sentSmsEnvelopes = {};
 
@@ -223,17 +225,18 @@ RadioInterfaceLayer.prototype = {
    */
   receiveMessage: function receiveMessage(msg) {
     debug("Received '" + msg.name + "' message from content process");
     switch (msg.name) {
       case "RIL:GetRilContext":
         // This message is sync.
         return this.rilContext;
       case "RIL:EnumerateCalls":
-        this.enumerateCalls();
+        this.saveRequestTarget(msg);
+        this.enumerateCalls(msg.json);
         break;
       case "RIL:GetMicrophoneMuted":
         // This message is sync.
         return this.microphoneMuted;
       case "RIL:SetMicrophoneMuted":
         this.microphoneMuted = msg.json;
         break;
       case "RIL:GetSpeakerEnabled":
@@ -265,36 +268,44 @@ RadioInterfaceLayer.prototype = {
         break;
       case "RIL:HoldCall":
         this.holdCall(msg.json);
         break;
       case "RIL:ResumeCall":
         this.resumeCall(msg.json);
         break;
       case "RIL:GetAvailableNetworks":
-        this.getAvailableNetworks(msg.json);
+        this.saveRequestTarget(msg);
+        this.getAvailableNetworks(msg.json.requestId);
         break;
       case "RIL:SelectNetwork":
+        this.saveRequestTarget(msg);
         this.selectNetwork(msg.json);
         break;
       case "RIL:SelectNetworkAuto":
-        this.selectNetworkAuto(msg.json);
+        this.saveRequestTarget(msg);
+        this.selectNetworkAuto(msg.json.requestId);
       case "RIL:GetCardLock":
+        this.saveRequestTarget(msg);
         this.getCardLock(msg.json);
         break;
       case "RIL:UnlockCardLock":
+        this.saveRequestTarget(msg);
         this.unlockCardLock(msg.json);
         break;
       case "RIL:SetCardLock":
+        this.saveRequestTarget(msg);
         this.setCardLock(msg.json);
         break;
       case "RIL:SendUSSD":
+        this.saveRequestTarget(msg);
         this.sendUSSD(msg.json);
         break;
       case "RIL:CancelUSSD":
+        this.saveRequestTarget(msg);
         this.cancelUSSD(msg.json);
         break;
     }
   },
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
@@ -317,17 +328,17 @@ RadioInterfaceLayer.prototype = {
         this.handleCallStateChange(message.call);
         break;
       case "callDisconnected":
         // This one will handle its own notifications.
         this.handleCallDisconnected(message.call);
         break;
       case "enumerateCalls":
         // This one will handle its own notifications.
-        this.handleEnumerateCalls(message.calls);
+        this.handleEnumerateCalls(message);
         break;
       case "callError":
         this.handleCallError(message);
         break;
       case "getAvailableNetworks":
         this.handleGetAvailableNetworks(message);
         break;
       case "selectNetwork":
@@ -430,16 +441,39 @@ RadioInterfaceLayer.prototype = {
         this.handleCancelUSSD(message);
         break;
       default:
         throw new Error("Don't know about this message type: " +
                         message.rilMessageType);
     }
   },
 
+  _messageManagerByRequest: null,
+  saveRequestTarget: function saveRequestTarget(msg) {
+    let requestId = msg.json.requestId;
+    if (!requestId) {
+      // The content is not interested in a response;
+      return;
+    }
+
+    let mm = msg.target.QueryInterface(Ci.nsIFrameMessageManager);
+    this._messageManagerByRequest[requestId] = mm;
+  },
+
+  _sendRequestResults: function _sendRequestResults(requestType, options) {
+    let target = this._messageManagerByRequest[options.requestId];
+    delete this._messageManagerByRequest[options.requestId];
+
+    if (!target) {
+      return;
+    }
+
+    target.sendAsyncMessage(requestType, options);
+  },
+
   updateNetworkInfo: function updateNetworkInfo(message) {
     let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE];
     let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
     let operatorMessage = message[RIL.NETWORK_INFO_OPERATOR];
     let selectionMessage = message[RIL.NETWORK_INFO_NETWORK_SELECTION_MODE];
 
     // Batch the *InfoChanged messages together
     if (voiceMessage) {
@@ -728,55 +762,55 @@ RadioInterfaceLayer.prototype = {
     this.updateCallAudioState();
     call.state = nsIRadioInterfaceLayer.CALL_STATE_DISCONNECTED;
     ppmm.sendAsyncMessage("RIL:CallStateChanged", call);
   },
 
   /**
    * Handle calls delivered in response to a 'enumerateCalls' request.
    */
-  handleEnumerateCalls: function handleEnumerateCalls(calls) {
-    debug("handleEnumerateCalls: " + JSON.stringify(calls));
-    for (let i in calls) {
-      calls[i].state = convertRILCallState(calls[i].state);
+  handleEnumerateCalls: function handleEnumerateCalls(options) {
+    debug("handleEnumerateCalls: " + JSON.stringify(options));
+    for (let i in options.calls) {
+      options.calls[i].state = convertRILCallState(options.calls[i].state);
     }
-    ppmm.sendAsyncMessage("RIL:EnumerateCalls", calls);
+    this._sendRequestResults("RIL:EnumerateCalls", options);
   },
 
   /**
    * Handle available networks returned by the 'getAvailableNetworks' request.
    */
   handleGetAvailableNetworks: function handleGetAvailableNetworks(message) {
     debug("handleGetAvailableNetworks: " + JSON.stringify(message));
 
-    ppmm.sendAsyncMessage("RIL:GetAvailableNetworks", message);
+    this._sendRequestResults("RIL:GetAvailableNetworks", message);
   },
 
   /**
    * Update network selection mode
    */
   updateNetworkSelectionMode: function updateNetworkSelectionMode(message) {
     debug("updateNetworkSelectionMode: " + JSON.stringify(message));
     ppmm.sendAsyncMessage("RIL:NetworkSelectionModeChanged", message);
   },
 
   /**
    * Handle "manual" network selection request.
    */
   handleSelectNetwork: function handleSelectNetwork(message) {
     debug("handleSelectNetwork: " + JSON.stringify(message));
-    ppmm.sendAsyncMessage("RIL:SelectNetwork", message);
+    this._sendRequestResults("RIL:SelectNetwork", message);
   },
 
   /**
    * Handle "automatic" network selection request.
    */
   handleSelectNetworkAuto: function handleSelectNetworkAuto(message) {
     debug("handleSelectNetworkAuto: " + JSON.stringify(message));
-    ppmm.sendAsyncMessage("RIL:SelectNetworkAuto", message);
+    this._sendRequestResults("RIL:SelectNetworkAuto", message);
   },
 
   /**
    * Handle call error.
    */
   handleCallError: function handleCallError(message) {
     ppmm.sendAsyncMessage("RIL:CallError", message);   
   },
@@ -952,36 +986,36 @@ RadioInterfaceLayer.prototype = {
    * Handle data call list.
    */
   handleDataCallList: function handleDataCallList(message) {
     this._deliverDataCallCallback("receiveDataCallList",
                                   [message.datacalls, message.datacalls.length]);
   },
 
   handleICCCardLockResult: function handleICCCardLockResult(message) {
-    ppmm.sendAsyncMessage("RIL:CardLockResult", message);
+    this._sendRequestResults("RIL:CardLockResult", message);
   },
 
   handleUSSDReceived: function handleUSSDReceived(ussd) {
     debug("handleUSSDReceived " + JSON.stringify(ussd));
     ppmm.sendAsyncMessage("RIL:UssdReceived", ussd);
   },
 
   handleSendUSSD: function handleSendUSSD(message) {
     debug("handleSendUSSD " + JSON.stringify(message));
     let messageType = message.success ? "RIL:SendUssd:Return:OK" :
                                         "RIL:SendUssd:Return:KO";
-    ppmm.sendAsyncMessage(messageType, message);
+    this._sendRequestResults(messageType, message);
   },
 
   handleCancelUSSD: function handleCancelUSSD(message) {
     debug("handleCancelUSSD " + JSON.stringify(message));
     let messageType = message.success ? "RIL:CancelUssd:Return:OK" :
                                         "RIL:CancelUssd:Return:KO";
-    ppmm.sendAsyncMessage(messageType, message);
+    this._sendRequestResults(messageType, message);
   },
 
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
         let setting = JSON.parse(data);
@@ -1060,19 +1094,20 @@ RadioInterfaceLayer.prototype = {
     debug("Setting radio power to " + value);
     this.worker.postMessage({rilMessageType: "setRadioPower", on: value});
   },
 
   rilContext: null,
 
   // Handle phone functions of nsIRILContentHelper
 
-  enumerateCalls: function enumerateCalls() {
+  enumerateCalls: function enumerateCalls(message) {
     debug("Requesting enumeration of calls for callback");
-    this.worker.postMessage({rilMessageType: "enumerateCalls"});
+    message.rilMessageType = "enumerateCalls";
+    this.worker.postMessage(message);
   },
 
   dial: function dial(number) {
     debug("Dialing " + number);
     this.worker.postMessage({rilMessageType: "dial",
                              number: number,
                              isDialEmergency: false});
   },
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2800,23 +2800,24 @@ let RIL = {
       return;
     }
     method.call(this, message);
   },
 
   /**
    * Get a list of current voice calls.
    */
-  enumerateCalls: function enumerateCalls() {
+  enumerateCalls: function enumerateCalls(options) {
     if (DEBUG) debug("Sending all current calls");
     let calls = [];
     for each (let call in this.currentCalls) {
       calls.push(call);
     }
-    this.sendDOMMessage({rilMessageType: "enumerateCalls", calls: calls});
+    options.calls = calls;
+    this.sendDOMMessage(options);
   },
 
   /**
    * Get a list of current data calls.
    */
   enumerateDataCalls: function enumerateDataCalls() {
     let datacall_list = [];
     for each (let datacall in this.currentDataCalls) {
@@ -3253,24 +3254,26 @@ RIL[REQUEST_SIM_IO] = function REQUEST_S
   this._processICCIO(options);
 };
 RIL[REQUEST_SEND_USSD] = function REQUEST_SEND_USSD(length, options) {
   if (DEBUG) {
     debug("REQUEST_SEND_USSD " + JSON.stringify(options)); 
   }
   options.rilMessageType = "sendussd";
   options.success = options.rilRequestError == 0 ? true : false;
+  options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   this.sendDOMMessage(options);
 };
 RIL[REQUEST_CANCEL_USSD] = function REQUEST_CANCEL_USSD(length, options) {
   if (DEBUG) {
     debug("REQUEST_CANCEL_USSD" + JSON.stringify(options));
   }
   options.rilMessageType = "cancelussd";
   options.success = options.rilRequestError == 0 ? true : false;
+  options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   this.sendDOMMessage(options);
 };
 RIL[REQUEST_GET_CLIR] = null;
 RIL[REQUEST_SET_CLIR] = null;
 RIL[REQUEST_QUERY_CALL_FORWARD_STATUS] = null;
 RIL[REQUEST_SET_CALL_FORWARD] = null;
 RIL[REQUEST_QUERY_CALL_WAITING] = null;
 RIL[REQUEST_SET_CALL_WAITING] = null;