Bug 744453 - B2G RIL: Network Friendly / APN connection retry policy. r=philikon
authorFernando Rodríguez Sela <frsela@tid.es>
Fri, 01 Jun 2012 14:09:59 -0700
changeset 95578 824f8d575f0f65e1d4257f40891eb55c4b852fce
parent 95577 e9472ce37d840a4dcee8bca2101cd6e1e37428e6
child 95579 0599752de89c3d93ed94d72107afb96efb228446
push id22819
push usereakhgari@mozilla.com
push dateSat, 02 Jun 2012 18:40:08 +0000
treeherdermozilla-central@f4a7c1a1f514 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon
bugs744453
milestone15.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 744453 - B2G RIL: Network Friendly / APN connection retry policy. r=philikon
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -279,16 +279,22 @@ RadioInterfaceLayer.prototype = {
         this.handleCallError(message);
         break;
       case "voiceregistrationstatechange":
         this.updateVoiceConnection(message);
         break;
       case "dataregistrationstatechange":
         this.updateDataConnection(message);
         break;
+      case "datacallerror":
+        // 3G Network revoked the data connection, possible unavailable APN
+        debug("Received data registration error message. Failed APN " +
+              Services.prefs.getCharPref("ril.data.apn"));
+        RILNetworkInterface.reset();
+        break;
       case "signalstrengthchange":
         this.handleSignalStrengthChange(message);
         break;
       case "operatorchange":
         this.handleOperatorChange(message);
         break;
       case "radiostatechange":
         this.handleRadioStateChange(message);
@@ -734,16 +740,17 @@ RadioInterfaceLayer.prototype = {
       case kMozSettingsChangedObserverTopic:
         let setting = JSON.parse(data);
         this.handleMozSettingsChanged(setting);
         break;
       case "xpcom-shutdown":
         for each (let msgname in RIL_IPC_MSG_NAMES) {
           ppmm.removeMessageListener(msgname, this);
         }
+        RILNetworkInterface.shutdown();
         ppmm = null;
         Services.obs.removeObserver(this, "xpcom-shutdown");
         Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
         break;
     }
   },
 
   // nsISettingsServiceCallback
@@ -1419,16 +1426,27 @@ let RILNetworkInterface = {
   NETWORK_STATE_DISCONNECTED:  Ci.nsINetworkInterface.DISCONNECTED,
 
   state: Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
 
   NETWORK_TYPE_WIFI:       Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
   NETWORK_TYPE_MOBILE:     Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
   NETWORK_TYPE_MOBILE_MMS: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS,
 
+  /**
+   * Standard values for the APN connection retry process
+   * Retry funcion: time(secs) = A * numer_of_retries^2 + B
+   */
+  NETWORK_APNRETRY_FACTOR: 8,
+  NETWORK_APNRETRY_ORIGIN: 3,
+  NETWORK_APNRETRY_MAXRETRIES: 10,
+
+  // Event timer for connection retries
+  timer: null,
+
   type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
 
   name: null,
 
   dhcp: false,
 
   // nsIRILDataCallback
 
@@ -1465,16 +1483,19 @@ let RILNetworkInterface = {
 
   // Helpers
 
   cid: null,
   registeredAsDataCallCallback: false,
   registeredAsNetworkInterface: false,
   connecting: false,
 
+  // APN failed connections. Retry counter
+  apnRetryCounter: 0,
+
   get mRIL() {
     delete this.mRIL;
     return this.mRIL = Cc["@mozilla.org/telephony/system-worker-manager;1"]
                          .getService(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIRadioInterfaceLayer);
   },
 
   get connected() {
@@ -1505,26 +1526,62 @@ let RILNetworkInterface = {
     }
     debug("Going to set up data connection with APN " + apn);
     this.mRIL.setupDataCall(RIL.DATACALL_RADIOTECHNOLOGY_GSM,
                             apn, user, passwd,
                             RIL.DATACALL_AUTH_PAP_OR_CHAP, "IP");
     this.connecting = true;
   },
 
+  reset: function reset() {
+    let apnRetryTimer;
+    this.connecting = false;
+    // We will retry the connection in increasing times
+    // based on the function: time = A * numer_of_retries^2 + B
+    if (this.apnRetryCounter >= this.NETWORK_APNRETRY_MAXRETRIES) {
+      this.apnRetryCounter = 0;
+      this.timer = null;
+      debug("Too many APN Connection retries - STOP retrying");
+      return;
+    }
+
+    apnRetryTimer = this.NETWORK_APNRETRY_FACTOR *
+                    (this.apnRetryCounter * this.apnRetryCounter) +
+                    this.NETWORK_APNRETRY_ORIGIN;
+    this.apnRetryCounter++;
+    debug("Data call - APN Connection Retry Timer (secs-counter): " +
+          apnRetryTimer + "-" + this.apnRetryCounter);
+
+    if (this.timer == null) {
+      // Event timer for connection retries
+      this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    }
+    this.timer.initWithCallback(this, apnRetryTimer * 1000,
+                                Ci.nsITimer.TYPE_ONE_SHOT);
+  },
+
   disconnect: function disconnect() {
     if (this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING ||
         this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) {
       return;
     }
     let reason = RIL.DATACALL_DEACTIVATE_NO_REASON;
     debug("Going to disconnet data connection " + this.cid);
     this.mRIL.deactivateDataCall(this.cid, reason);
   },
 
+  // Entry method for timer events. Used to reconnect to a failed APN
+  notify: function(timer) {
+    RILNetworkInterface.connect();
+  },
+
+  shutdown: function() {
+    this.timer = null;
+  }
+
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- RadioInterfaceLayer: " + s + "\n");
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2810,16 +2810,18 @@ RIL.readSetupDataCall_v5 = function read
   options.gw = gw;
   options.active = DATACALL_ACTIVE_UNKNOWN;
   options.state = GECKO_NETWORK_STATE_CONNECTING;
   return options;
 };
 
 RIL[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) {
   if (options.rilRequestError) {
+    // On Data Call error, we shall notify caller
+    this.sendDOMMessage({type: "datacallerror"});
     return;
   }
 
   if (RILQUIRKS_V5_LEGACY) {
     this.readSetupDataCall_v5(options);
     this.currentDataCalls[options.cid] = options;
     this.sendDOMMessage({type: "datacallstatechange",
                          datacall: options});