2727import android .net .LinkCapabilities ;
2828import android .net .LinkProperties ;
2929import android .net .NetworkInfo ;
30+ import android .net .TrafficStats ;
3031import android .net .wifi .WifiManager ;
3132import android .os .AsyncResult ;
3233import android .os .Bundle ;
3334import android .os .Handler ;
3435import android .os .Message ;
3536import android .os .Messenger ;
37+ import android .os .SystemClock ;
3638import android .os .SystemProperties ;
3739import android .preference .PreferenceManager ;
3840import android .provider .Settings ;
5658 */
5759public abstract class DataConnectionTracker extends Handler {
5860 protected static final boolean DBG = true ;
61+ protected static final boolean VDBG = false ;
5962
6063 /**
6164 * IDLE: ready to start data connection setup, default state
@@ -114,8 +117,8 @@ public enum Activity {
114117 protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14 ;
115118 protected static final int EVENT_DISCONNECT_DONE = BASE + 15 ;
116119 protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16 ;
117- protected static final int EVENT_START_NETSTAT_POLL = BASE + 17 ;
118- protected static final int EVENT_START_RECOVERY = BASE + 18 ;
120+ protected static final int EVENT_DATA_STALL_ALARM = BASE + 17 ;
121+ protected static final int EVENT_DO_RECOVERY = BASE + 18 ;
119122 protected static final int EVENT_APN_CHANGED = BASE + 19 ;
120123 protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20 ;
121124 protected static final int EVENT_NV_READY = BASE + 21 ;
@@ -189,19 +192,16 @@ public enum Activity {
189192
190193 /**
191194 * After detecting a potential connection problem, this is the max number
192- * of subsequent polls before attempting a radio reset. At this point,
193- * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
194- * poll for about 2 more minutes.
195+ * of subsequent polls before attempting recovery.
195196 */
196197 protected static final int NO_RECV_POLL_LIMIT = 24 ;
197-
198198 // 1 sec. default polling interval when screen is on.
199199 protected static final int POLL_NETSTAT_MILLIS = 1000 ;
200200 // 10 min. default polling interval when screen is off.
201201 protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000 *60 *10 ;
202202 // 2 min for round trip time
203203 protected static final int POLL_LONGEST_RTT = 120 * 1000 ;
204- // 10 for packets without ack
204+ // Default sent packets without ack which triggers initial recovery steps
205205 protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10 ;
206206 // how long to wait before switching back to default APN
207207 protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000 ;
@@ -210,6 +210,13 @@ public enum Activity {
210210 // represents an invalid IP address
211211 protected static final String NULL_IP = "0.0.0.0" ;
212212
213+ // Default for the data stall alarm
214+ protected static final int DATA_STALL_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 3 ;
215+ // If attempt is less than this value we're doing first level recovery
216+ protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1 ;
217+ // Tag for tracking stale alarms
218+ protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag" ;
219+
213220 // TODO: See if we can remove INTENT_RECONNECT_ALARM
214221 // having to have different values for GSM and
215222 // CDMA. If so we can then remove the need for
@@ -240,11 +247,19 @@ public enum Activity {
240247
241248 protected long mTxPkts ;
242249 protected long mRxPkts ;
243- protected long mSentSinceLastRecv ;
244250 protected int mNetStatPollPeriod ;
245- protected int mNoRecvPollCount = 0 ;
246251 protected boolean mNetStatPollEnabled = false ;
247252
253+ protected TxRxSum mDataStallTxRxSum = new TxRxSum (0 , 0 );
254+ // Used to track stale data stall alarms.
255+ protected int mDataStallAlarmTag = (int ) SystemClock .elapsedRealtime ();
256+ // The current data stall alarm intent
257+ protected PendingIntent mDataStallAlarmIntent = null ;
258+ // Number of packets sent since the last received packet
259+ protected long mSentSinceLastRecv ;
260+ // Controls when a simple recovery attempt it to be tried
261+ protected int mNoRecvPollCount = 0 ;
262+
248263 // wifi connection status will be updated by sticky intent
249264 protected boolean mIsWifiConnected = false ;
250265
@@ -313,7 +328,8 @@ public void onReceive(Context context, Intent intent)
313328 } else if (action .startsWith (getActionIntentReconnectAlarm ())) {
314329 log ("Reconnect alarm. Previous state was " + mState );
315330 onActionIntentReconnectAlarm (intent );
316-
331+ } else if (action .equals (getActionIntentDataStallAlarm ())) {
332+ onActionIntentDataStallAlarm (intent );
317333 } else if (action .equals (WifiManager .NETWORK_STATE_CHANGED_ACTION )) {
318334 final android .net .NetworkInfo networkInfo = (NetworkInfo )
319335 intent .getParcelableExtra (WifiManager .EXTRA_NETWORK_INFO );
@@ -363,6 +379,71 @@ public void onChange(boolean selfChange) {
363379 }
364380 }
365381
382+ /**
383+ * Maintian the sum of transmit and receive packets.
384+ *
385+ * The packet counts are initizlied and reset to -1 and
386+ * remain -1 until they can be updated.
387+ */
388+ public class TxRxSum {
389+ public long txPkts ;
390+ public long rxPkts ;
391+
392+ public TxRxSum () {
393+ reset ();
394+ }
395+
396+ public TxRxSum (long txPkts , long rxPkts ) {
397+ this .txPkts = txPkts ;
398+ this .rxPkts = rxPkts ;
399+ }
400+
401+ public TxRxSum (TxRxSum sum ) {
402+ txPkts = sum .txPkts ;
403+ rxPkts = sum .rxPkts ;
404+ }
405+
406+ public void reset () {
407+ txPkts = -1 ;
408+ rxPkts = -1 ;
409+ }
410+
411+ public String toString () {
412+ return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}" ;
413+ }
414+
415+ public void updateTxRxSum () {
416+ boolean txUpdated = false , rxUpdated = false ;
417+ long txSum = 0 , rxSum = 0 ;
418+ for (ApnContext apnContext : mApnContexts .values ()) {
419+ if (apnContext .getState () == State .CONNECTED ) {
420+ DataConnectionAc dcac = apnContext .getDataConnectionAc ();
421+ if (dcac == null ) continue ;
422+
423+ LinkProperties linkProp = dcac .getLinkPropertiesSync ();
424+ if (linkProp == null ) continue ;
425+
426+ String iface = linkProp .getInterfaceName ();
427+
428+ if (iface != null ) {
429+ long stats = TrafficStats .getTxPackets (iface );
430+ if (stats > 0 ) {
431+ txUpdated = true ;
432+ txSum += stats ;
433+ }
434+ stats = TrafficStats .getRxPackets (iface );
435+ if (stats > 0 ) {
436+ rxUpdated = true ;
437+ rxSum += stats ;
438+ }
439+ }
440+ }
441+ }
442+ if (txUpdated ) this .txPkts = txSum ;
443+ if (rxUpdated ) this .rxPkts = rxSum ;
444+ }
445+ }
446+
366447 protected boolean isDataSetupCompleteOk (AsyncResult ar ) {
367448 if (ar .exception != null ) {
368449 if (DBG ) log ("isDataSetupCompleteOk return false, ar.result=" + ar .result );
@@ -394,6 +475,13 @@ protected void onActionIntentReconnectAlarm(Intent intent) {
394475 sendMessage (obtainMessage (EVENT_TRY_SETUP_DATA ));
395476 }
396477
478+ protected void onActionIntentDataStallAlarm (Intent intent ) {
479+ if (VDBG ) log ("onActionIntentDataStallAlarm: action=" + intent .getAction ());
480+ Message msg = obtainMessage (EVENT_DATA_STALL_ALARM , intent .getAction ());
481+ msg .arg1 = intent .getIntExtra (DATA_STALL_ALARM_TAG_EXTRA , 0 );
482+ sendMessage (msg );
483+ }
484+
397485 /**
398486 * Default constructor
399487 */
@@ -529,6 +617,7 @@ private void handleDataOnRoamingChange() {
529617
530618 // abstract methods
531619 protected abstract String getActionIntentReconnectAlarm ();
620+ protected abstract String getActionIntentDataStallAlarm ();
532621 protected abstract void startNetStatPoll ();
533622 protected abstract void stopNetStatPoll ();
534623 protected abstract void restartRadio ();
@@ -553,6 +642,10 @@ private void handleDataOnRoamingChange() {
553642 protected abstract void onCleanUpAllConnections (String cause );
554643 protected abstract boolean isDataPossible (String apnType );
555644
645+ protected void onDataStallAlarm (int tag ) {
646+ loge ("onDataStallAlarm: not impleted tag=" + tag );
647+ }
648+
556649 @ Override
557650 public void handleMessage (Message msg ) {
558651 switch (msg .what ) {
@@ -575,6 +668,10 @@ public void handleMessage(Message msg) {
575668 onTrySetupData (reason );
576669 break ;
577670
671+ case EVENT_DATA_STALL_ALARM :
672+ onDataStallAlarm (msg .arg1 );
673+ break ;
674+
578675 case EVENT_ROAMING_OFF :
579676 if (getDataOnRoamingEnabled () == false ) {
580677 resetAllRetryCounts ();
0 commit comments