Bug 1074037 - B2G RIL: refine DataCall's canHandleApn() decision logic. r=edgar
authorJessica Jong <jjong@mozilla.com>
Thu, 09 Oct 2014 02:24:00 +0800
changeset 232938 dc476f38e60f41e17d00318998c9cf7832365a7e
parent 232937 1f504b24522acfa1e06e8c29906d627c67881492
child 232939 629c28f4c2e5f819fe64b07f61fb30a89b7abf31
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedgar
bugs1074037
milestone35.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 1074037 - B2G RIL: refine DataCall's canHandleApn() decision logic. r=edgar
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1155,27 +1155,35 @@ DataConnectionHandler.prototype = {
         return Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS;
       case "dun":
         return Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN;
       default:
         return Ci.nsINetworkInterface.NETWORK_TYPE_UNKNOWN;
      }
   },
 
+  _compareDataCallOptions: function(dataCall, newDataCall) {
+    return dataCall.apnProfile.apn == newDataCall.apn &&
+           dataCall.apnProfile.user == newDataCall.user &&
+           dataCall.apnProfile.password == newDataCall.password &&
+           dataCall.chappap == newDataCall.chappap &&
+           dataCall.pdptype == newDataCall.pdptype;
+  },
+
   _deliverDataCallMessage: function(name, args) {
     for (let i = 0; i < this._dataCalls.length; i++) {
       let datacall = this._dataCalls[i];
-      // Send message only to the DataCall that matches apn.
+      // Send message only to the DataCall that matches the data call options.
       // Currently, args always contain only one datacall info.
-      if (!args[0].apn || args[0].apn != datacall.apnProfile.apn) {
+      if (!this._compareDataCallOptions(datacall, args[0])) {
         continue;
       }
       // Do not deliver message to DataCall that contains cid but mistmaches
       // with the cid in the current message.
-      if (args[0].cid && datacall.linkInfo.cid &&
+      if (args[0].cid !== undefined && datacall.linkInfo.cid != null &&
           args[0].cid != datacall.linkInfo.cid) {
         continue;
       }
 
       try {
         let handler = datacall[name];
         if (typeof handler !== "function") {
           throw new Error("No handler for " + name);
@@ -1481,19 +1489,27 @@ DataConnectionHandler.prototype = {
 
   /**
    * Handle data errors.
    */
   handleDataCallError: function(message) {
     // Notify data call error only for data APN
     let networkInterface = this.dataNetworkInterfaces.get("default");
     if (networkInterface && networkInterface.enabled) {
-      let apnSetting = networkInterface.apnSetting;
-      if (message.apn == apnSetting.apn) {
-        gMobileConnectionService.notifyDataError(this.clientId, message);
+      let dataCall = networkInterface.dataCall;
+      // If there is a cid, compare cid; otherwise it is probably an error on
+      // data call setup.
+      if (message.cid !== undefined) {
+        if (message.cid == dataCall.linkInfo.cid) {
+          gMobileConnectionService.notifyDataError(this.clientId, message);
+        }
+      } else {
+        if (this._compareDataCallOptions(dataCall, message)) {
+          gMobileConnectionService.notifyDataError(this.clientId, message);
+        }
       }
     }
 
     this._deliverDataCallMessage("dataCallError", [message]);
   },
 
   /**
    * Handle data call state changes.
@@ -3889,16 +3905,22 @@ DataCall.prototype = {
   timer: null,
 
   // APN failed connections. Retry counter
   apnRetryCounter: 0,
 
   // Array to hold RILNetworkInterfaces that requested this DataCall.
   requestedNetworkIfaces: null,
 
+  // Holds the pdp type sent to ril worker.
+  pdptype: null,
+
+  // Holds the authentication type sent to ril worker.
+  chappap: null,
+
   dataCallError: function(message) {
     if (DEBUG) this.debug("Data call error on APN: " + message.apn);
     this.state = RIL.GECKO_NETWORK_STATE_DISCONNECTED;
     this.retry();
   },
 
   dataCallStateChanged: function(datacall) {
     if (DEBUG) {
@@ -4007,31 +4029,42 @@ DataCall.prototype = {
       if (this.requestedNetworkIfaces[i].type == type) {
         return true;
       }
     }
     return false;
   },
 
   canHandleApn: function(apnSetting) {
-    // TODO: compare authtype?
-    return (this.apnProfile.apn == apnSetting.apn &&
-            (this.apnProfile.user || '') == (apnSetting.user || '') &&
-            (this.apnProfile.password || '') == (apnSetting.password || ''));
+    let isIdentical = this.apnProfile.apn == apnSetting.apn &&
+                      (this.apnProfile.user || '') == (apnSetting.user || '') &&
+                      (this.apnProfile.password || '') == (apnSetting.password || '') &&
+                      (this.apnProfile.authType || '') == (apnSetting.authtype || '');
+
+    if (RILQUIRKS_HAVE_IPV6) {
+      isIdentical = isIdentical &&
+                    (this.apnProfile.protocol || '') == (apnSetting.protocol || '') &&
+                    (this.apnProfile.roaming_protocol || '') == (apnSetting.roaming_protocol || '');
+    }
+
+    return isIdentical;
   },
 
   reset: function() {
     this.linkInfo.cid = null;
     this.linkInfo.ifname = null;
     this.linkInfo.ips = [];
     this.linkInfo.prefixLengths = [];
     this.linkInfo.dnses = [];
     this.linkInfo.gateways = [];
 
     this.state = RIL.GECKO_NETWORK_STATE_UNKNOWN;
+
+    this.chappap = null;
+    this.pdptype = null;
   },
 
   connect: function(networkInterface) {
     if (DEBUG) this.debug("connect: " + networkInterface.type);
 
     if (this.requestedNetworkIfaces.indexOf(networkInterface) == -1) {
       this.requestedNetworkIfaces.push(networkInterface);
     }
@@ -4074,38 +4107,41 @@ DataCall.prototype = {
     if (dataInfo == null ||
         dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED ||
         dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) {
       return;
     }
 
     let radioTechType = dataInfo.type;
     let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
-    let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnProfile.authtype);
+    let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnProfile.authType);
     // Use the default authType if the value in database is invalid.
     // For the case that user might not select the authentication type.
     if (authType == -1) {
       if (DEBUG) {
         this.debug("Invalid authType " + this.apnProfile.authtype);
       }
       authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
     }
+    this.chappap = authType;
+
     let pdpType = RIL.GECKO_DATACALL_PDP_TYPE_IP;
     if (RILQUIRKS_HAVE_IPV6) {
       pdpType = !dataInfo.roaming
               ? this.apnProfile.protocol
               : this.apnProfile.roaming_protocol;
       if (RIL.RIL_DATACALL_PDP_TYPES.indexOf(pdpType) < 0) {
         if (DEBUG) {
           this.debug("Invalid pdpType '" + pdpType + "', using '" +
                      RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'");
         }
         pdpType = RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT;
       }
     }
+    this.pdptype = pdpType;
 
     let radioInterface = this.gRIL.getRadioInterface(this.clientId);
     radioInterface.sendWorkerMessage("setupDataCall", {
       radioTech: radioTechnology,
       apn: this.apnProfile.apn,
       user: this.apnProfile.user,
       passwd: this.apnProfile.password,
       chappap: authType,
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -4123,20 +4123,18 @@ RilObject.prototype = {
     return "identical";
   },
 
   _processDataCallList: function(datacalls, newDataCallOptions) {
     // Check for possible PDP errors: We check earlier because the datacall
     // can be removed if is the same as the current one.
     for each (let newDataCall in datacalls) {
       if (newDataCall.status != DATACALL_FAIL_NONE) {
-        if (newDataCallOptions) {
-          newDataCall.apn = newDataCallOptions.apn;
-        }
-        this._sendDataCallError(newDataCall, newDataCall.status);
+        this._sendDataCallError(newDataCallOptions || newDataCall,
+                                newDataCall.status);
       }
     }
 
     for each (let currentDataCall in this.currentDataCalls) {
       let updatedDataCall;
       if (datacalls) {
         updatedDataCall = datacalls[currentDataCall.cid];
         delete datacalls[currentDataCall.cid];