diff options
author | Wink Saville <wink@google.com> | 2011-11-03 18:52:58 -0700 |
---|---|---|
committer | Wink Saville <wink@google.com> | 2011-11-03 18:52:58 -0700 |
commit | 2861d23d660c577c65faa7dfebd66d5b6f3f1a56 (patch) | |
tree | d844122c58941f67a3b9ecf1166780f7323230c7 /telephony/java | |
parent | 8c49b81b5971c3fd254c4ecd862d1a32b1917edb (diff) | |
download | frameworks_base-2861d23d660c577c65faa7dfebd66d5b6f3f1a56.zip frameworks_base-2861d23d660c577c65faa7dfebd66d5b6f3f1a56.tar.gz frameworks_base-2861d23d660c577c65faa7dfebd66d5b6f3f1a56.tar.bz2 |
Separate data stall detection and recovery from net stats.
Also use the AlarmManager instead of messages so the delays
are consistent whether sleeping or not.
Bug: 5534004
Change-Id: I24118b30214dddf8183c1200a89555d6c528e606
Diffstat (limited to 'telephony/java')
3 files changed, 346 insertions, 163 deletions
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 97e7aa3..5b13603 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -27,12 +27,14 @@ import android.database.ContentObserver; import android.net.LinkCapabilities; import android.net.LinkProperties; import android.net.NetworkInfo; +import android.net.TrafficStats; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; +import android.os.SystemClock; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Settings; @@ -56,6 +58,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class DataConnectionTracker extends Handler { protected static final boolean DBG = true; + protected static final boolean VDBG = false; /** * IDLE: ready to start data connection setup, default state @@ -114,8 +117,8 @@ public abstract class DataConnectionTracker extends Handler { protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14; protected static final int EVENT_DISCONNECT_DONE = BASE + 15; protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16; - protected static final int EVENT_START_NETSTAT_POLL = BASE + 17; - protected static final int EVENT_START_RECOVERY = BASE + 18; + protected static final int EVENT_DATA_STALL_ALARM = BASE + 17; + protected static final int EVENT_DO_RECOVERY = BASE + 18; protected static final int EVENT_APN_CHANGED = BASE + 19; protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20; protected static final int EVENT_NV_READY = BASE + 21; @@ -189,19 +192,16 @@ public abstract class DataConnectionTracker extends Handler { /** * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting a radio reset. At this point, - * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to - * poll for about 2 more minutes. + * of subsequent polls before attempting recovery. */ protected static final int NO_RECV_POLL_LIMIT = 24; - // 1 sec. default polling interval when screen is on. protected static final int POLL_NETSTAT_MILLIS = 1000; // 10 min. default polling interval when screen is off. protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; // 2 min for round trip time protected static final int POLL_LONGEST_RTT = 120 * 1000; - // 10 for packets without ack + // Default sent packets without ack which triggers initial recovery steps protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; // how long to wait before switching back to default APN protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; @@ -210,6 +210,13 @@ public abstract class DataConnectionTracker extends Handler { // represents an invalid IP address protected static final String NULL_IP = "0.0.0.0"; + // Default for the data stall alarm + protected static final int DATA_STALL_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 3; + // If attempt is less than this value we're doing first level recovery + protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1; + // Tag for tracking stale alarms + protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag"; + // TODO: See if we can remove INTENT_RECONNECT_ALARM // having to have different values for GSM and // CDMA. If so we can then remove the need for @@ -240,11 +247,19 @@ public abstract class DataConnectionTracker extends Handler { protected long mTxPkts; protected long mRxPkts; - protected long mSentSinceLastRecv; protected int mNetStatPollPeriod; - protected int mNoRecvPollCount = 0; protected boolean mNetStatPollEnabled = false; + protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); + // Used to track stale data stall alarms. + protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); + // The current data stall alarm intent + protected PendingIntent mDataStallAlarmIntent = null; + // Number of packets sent since the last received packet + protected long mSentSinceLastRecv; + // Controls when a simple recovery attempt it to be tried + protected int mNoRecvPollCount = 0; + // wifi connection status will be updated by sticky intent protected boolean mIsWifiConnected = false; @@ -313,7 +328,8 @@ public abstract class DataConnectionTracker extends Handler { } else if (action.startsWith(getActionIntentReconnectAlarm())) { log("Reconnect alarm. Previous state was " + mState); onActionIntentReconnectAlarm(intent); - + } else if (action.equals(getActionIntentDataStallAlarm())) { + onActionIntentDataStallAlarm(intent); } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { final android.net.NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); @@ -363,6 +379,71 @@ public abstract class DataConnectionTracker extends Handler { } } + /** + * Maintian the sum of transmit and receive packets. + * + * The packet counts are initizlied and reset to -1 and + * remain -1 until they can be updated. + */ + public class TxRxSum { + public long txPkts; + public long rxPkts; + + public TxRxSum() { + reset(); + } + + public TxRxSum(long txPkts, long rxPkts) { + this.txPkts = txPkts; + this.rxPkts = rxPkts; + } + + public TxRxSum(TxRxSum sum) { + txPkts = sum.txPkts; + rxPkts = sum.rxPkts; + } + + public void reset() { + txPkts = -1; + rxPkts = -1; + } + + public String toString() { + return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; + } + + public void updateTxRxSum() { + boolean txUpdated = false, rxUpdated = false; + long txSum = 0, rxSum = 0; + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getState() == State.CONNECTED) { + DataConnectionAc dcac = apnContext.getDataConnectionAc(); + if (dcac == null) continue; + + LinkProperties linkProp = dcac.getLinkPropertiesSync(); + if (linkProp == null) continue; + + String iface = linkProp.getInterfaceName(); + + if (iface != null) { + long stats = TrafficStats.getTxPackets(iface); + if (stats > 0) { + txUpdated = true; + txSum += stats; + } + stats = TrafficStats.getRxPackets(iface); + if (stats > 0) { + rxUpdated = true; + rxSum += stats; + } + } + } + } + if (txUpdated) this.txPkts = txSum; + if (rxUpdated) this.rxPkts = rxSum; + } + } + protected boolean isDataSetupCompleteOk(AsyncResult ar) { if (ar.exception != null) { if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result); @@ -394,6 +475,13 @@ public abstract class DataConnectionTracker extends Handler { sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } + protected void onActionIntentDataStallAlarm(Intent intent) { + if (VDBG) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); + Message msg = obtainMessage(EVENT_DATA_STALL_ALARM, intent.getAction()); + msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0); + sendMessage(msg); + } + /** * Default constructor */ @@ -529,6 +617,7 @@ public abstract class DataConnectionTracker extends Handler { // abstract methods protected abstract String getActionIntentReconnectAlarm(); + protected abstract String getActionIntentDataStallAlarm(); protected abstract void startNetStatPoll(); protected abstract void stopNetStatPoll(); protected abstract void restartRadio(); @@ -553,6 +642,10 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onCleanUpAllConnections(String cause); protected abstract boolean isDataPossible(String apnType); + protected void onDataStallAlarm(int tag) { + loge("onDataStallAlarm: not impleted tag=" + tag); + } + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -575,6 +668,10 @@ public abstract class DataConnectionTracker extends Handler { onTrySetupData(reason); break; + case EVENT_DATA_STALL_ALARM: + onDataStallAlarm(msg.arg1); + break; + case EVENT_ROAMING_OFF: if (getDataOnRoamingEnabled() == false) { resetAllRetryCounts(); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index f5d05a1..5889372 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -69,6 +69,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.cdma-reconnect"; + private static final String INTENT_DATA_STALL_ALARM = + "com.android.internal.telephony.cdma-data-stall"; + + /** * Constants for the data connection activity: * physical link down/up @@ -149,6 +153,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } @Override + protected String getActionIntentDataStallAlarm() { + return INTENT_DATA_STALL_ALARM; + } + + @Override protected void setState(State s) { if (DBG) log ("setState: " + s); if (mState != s) { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index e166401..b1684f9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -96,22 +96,37 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; - // Count of PDP reset attempts; reset when we see incoming, - // call reRegisterNetwork, or pingTest succeeds. - private int mPdpResetCount = 0; - // Recovery action taken in case of data stall - enum RecoveryAction {REREGISTER, RADIO_RESTART, RADIO_RESET}; - private RecoveryAction mRecoveryAction = RecoveryAction.REREGISTER; - + class RecoveryAction { + public static final int GET_DATA_CALL_LIST = 0; + public static final int CLEANUP = 1; + public static final int REREGISTER = 2; + public static final int RADIO_RESTART = 3; + public static final int RADIO_RESET = 4; + } + public int getRecoveryAction() { + int action = Settings.System.getInt(mPhone.getContext().getContentResolver(), + "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST); + if (VDBG) log("getRecoveryAction: " + action); + return action; + } + public void putRecoveryAction(int action) { + Settings.System.putInt(mPhone.getContext().getContentResolver(), + "radio.data.stall.recovery.action", action); + if (VDBG) log("putRecoveryAction: " + action); + } //***** Constants private static final int POLL_PDP_MILLIS = 5 * 1000; - private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; + private static final String INTENT_RECONNECT_ALARM = + "com.android.internal.telephony.gprs-reconnect"; private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "type"; + private static final String INTENT_DATA_STALL_ALARM = + "com.android.internal.telephony.gprs-data-stall"; + static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); static final String APN_ID = "apn_id"; private boolean canSetPreferApn = false; @@ -163,6 +178,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { p.getServiceStateTracker().registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); + // install reconnect intent filter for this data connection. + IntentFilter filter = new IntentFilter(); + filter.addAction(INTENT_DATA_STALL_ALARM); + p.getContext().registerReceiver(mIntentReceiver, filter, null, p); + mDataConnectionTracker = this; mResolver = mPhone.getContext().getContentResolver(); @@ -241,6 +261,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return INTENT_RECONNECT_ALARM; } + @Override + protected String getActionIntentDataStallAlarm() { + return INTENT_DATA_STALL_ALARM; + } + private ApnContext addApnContext(String type) { ApnContext apnContext = new ApnContext(type, LOG_TAG); apnContext.setDependencyMet(false); @@ -552,6 +577,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); stopNetStatPoll(); + stopDataStallAlarm(); notifyDataConnection(Phone.REASON_DATA_DETACHED); } @@ -560,6 +586,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (getOverallState() == State.CONNECTED) { if (DBG) log("onDataConnectionAttached: start polling notify attached"); startNetStatPoll(); + startDataStallAlarm(); notifyDataConnection(Phone.REASON_DATA_ATTACHED); } else { // update APN availability so that APN can be enabled. @@ -764,6 +791,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } stopNetStatPoll(); + stopDataStallAlarm(); + // TODO: Do we need mRequestedApnType? mRequestedApnType = Phone.APN_TYPE_DEFAULT; } @@ -1238,6 +1267,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // setState(State.CONNECTED); mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); startNetStatPoll(); + startDataStallAlarm(); // reset reconnect timer apnContext.getDataConnection().resetRetryCount(); } @@ -1252,59 +1282,60 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void resetPollStats() { mTxPkts = -1; mRxPkts = -1; - mSentSinceLastRecv = 0; mNetStatPollPeriod = POLL_NETSTAT_MILLIS; - mNoRecvPollCount = 0; } private void doRecovery() { if (getOverallState() == State.CONNECTED) { - int maxPdpReset = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, - DEFAULT_MAX_PDP_RESET_FAIL); - if (mPdpResetCount < maxPdpReset) { - mPdpResetCount++; - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv); - if (DBG) log("doRecovery() cleanup all connections mPdpResetCount < max"); + // Go through a series of recovery steps, each action transitions to the next action + int recoveryAction = getRecoveryAction(); + switch (recoveryAction) { + case RecoveryAction.GET_DATA_CALL_LIST: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, + mSentSinceLastRecv); + if (DBG) log("doRecovery() get data call list"); + mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED)); + putRecoveryAction(RecoveryAction.CLEANUP); + break; + case RecoveryAction.CLEANUP: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv); + if (DBG) log("doRecovery() cleanup all connections"); cleanUpAllConnections(true, Phone.REASON_PDP_RESET); - } else { - mPdpResetCount = 0; - switch (mRecoveryAction) { - case REREGISTER: - EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv); - if (DBG) log("doRecovery() re-register getting preferred network type"); - mPhone.getServiceStateTracker().reRegisterNetwork(null); - mRecoveryAction = RecoveryAction.RADIO_RESTART; - break; - case RADIO_RESTART: - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv); - if (DBG) log("restarting radio"); - mRecoveryAction = RecoveryAction.RADIO_RESET; - restartRadio(); - break; - case RADIO_RESET: - // This is in case radio restart has not recovered the data. - // It will set an additional "gsm.radioreset" property to tell - // RIL or system to take further action. - // The implementation of hard reset recovery action is up to OEM product. - // Once gsm.radioreset property is consumed, it is expected to set back - // to false by RIL. - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, -1); - if (DBG) log("restarting radio with reset indication"); - SystemProperties.set("gsm.radioreset", "true"); - // give 1 sec so property change can be notified. - try { - Thread.sleep(1000); - } catch (InterruptedException e) {} - restartRadio(); - break; - default: - throw new RuntimeException("doRecovery: Invalid mRecoveryAction " + - mRecoveryAction); - } + putRecoveryAction(RecoveryAction.REREGISTER); + break; + case RecoveryAction.REREGISTER: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, mSentSinceLastRecv); + if (DBG) log("doRecovery() re-register"); + mPhone.getServiceStateTracker().reRegisterNetwork(null); + putRecoveryAction(RecoveryAction.RADIO_RESTART); + break; + case RecoveryAction.RADIO_RESTART: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RESTART, mSentSinceLastRecv); + if (DBG) log("restarting radio"); + putRecoveryAction(RecoveryAction.RADIO_RESET); + restartRadio(); + break; + case RecoveryAction.RADIO_RESET: + // This is in case radio restart has not recovered the data. + // It will set an additional "gsm.radioreset" property to tell + // RIL or system to take further action. + // The implementation of hard reset recovery action is up to OEM product. + // Once gsm.radioreset property is consumed, it is expected to set back + // to false by RIL. + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RESTART_WITH_PROP, -1); + if (DBG) log("restarting radio with gsm.radioreset to true"); + SystemProperties.set("gsm.radioreset", "true"); + // give 1 sec so property change can be notified. + try { + Thread.sleep(1000); + } catch (InterruptedException e) {} + restartRadio(); + putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); + break; + default: + throw new RuntimeException("doRecovery: Invalid recoveryAction=" + + recoveryAction); } - } else { - if (DBG) log("doRecovery(): ignore, we're not connected"); } } @@ -1342,119 +1373,130 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); } - private Runnable mPollNetStat = new Runnable() - { - - public void run() { - long sent, received; - long preTxPkts = -1, preRxPkts = -1; - Activity newActivity; + private void updateDataStallInfo() { + long sent, received; - preTxPkts = mTxPkts; - preRxPkts = mRxPkts; + TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); + mDataStallTxRxSum.updateTxRxSum(); - long txSum = 0, rxSum = 0; - for (ApnContext apnContext : mApnContexts.values()) { - if (apnContext.getState() == State.CONNECTED) { - DataConnectionAc dcac = apnContext.getDataConnectionAc(); - if (dcac == null) continue; + if (VDBG) { + log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + + " preTxRxSum=" + preTxRxSum); + } - LinkProperties linkProp = dcac.getLinkPropertiesSync(); - if (linkProp == null) continue; + sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; + received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; - String iface = linkProp.getInterfaceName(); + if (VDBG) { + if (SystemProperties.getBoolean("radio.test.data.stall", false)) { + log("updateDataStallInfo: radio.test.data.stall true received = 0;"); + received = 0; + } + } + if ( sent > 0 && received > 0 ) { + if (VDBG) log("updateDataStallInfo: IN/OUT"); + mSentSinceLastRecv = 0; + putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); + } else if (sent > 0 && received == 0) { + if (mPhone.getState() == Phone.State.IDLE) { + mSentSinceLastRecv += sent; + } else { + mSentSinceLastRecv = 0; + } + if (DBG) { + log("updateDataStallInfo: OUT sent=" + sent + + " mSentSinceLastRecv=" + mSentSinceLastRecv); + } + } else if (sent == 0 && received > 0) { + if (VDBG) log("updateDataStallInfo: IN"); + mSentSinceLastRecv = 0; + putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); + } else { + if (VDBG) log("updateDataStallInfo: NONE"); + } + } - if (iface != null) { - long stats = TrafficStats.getTxPackets(iface); - if (stats > 0) txSum += stats; - stats = TrafficStats.getRxPackets(iface); - if (stats > 0) rxSum += stats; - } - } + @Override + protected void onDataStallAlarm(int tag) { + if (mDataStallAlarmTag != tag) { + if (DBG) { + log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); } + return; + } + updateDataStallInfo(); - mTxPkts = txSum; - mRxPkts = rxSum; + int hangWatchdogTrigger = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + NUMBER_SENT_PACKETS_OF_HANG); - // log("tx " + mTxPkts + " rx " + mRxPkts); + if (mSentSinceLastRecv >= hangWatchdogTrigger) { + if (DBG) { + log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction()); + } + sendMessage(obtainMessage(EVENT_DO_RECOVERY)); + } else { + if (VDBG) { + log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + + " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); + } + } + startDataStallAlarm(); + } - if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = mTxPkts - preTxPkts; - received = mRxPkts - preRxPkts; - if ( sent > 0 && received > 0 ) { - mSentSinceLastRecv = 0; - newActivity = Activity.DATAINANDOUT; - mPdpResetCount = 0; - mRecoveryAction = RecoveryAction.REREGISTER; - } else if (sent > 0 && received == 0) { - if (mPhone.getState() == Phone.State.IDLE) { - mSentSinceLastRecv += sent; - } else { - mSentSinceLastRecv = 0; - } - newActivity = Activity.DATAOUT; - } else if (sent == 0 && received > 0) { - mSentSinceLastRecv = 0; - newActivity = Activity.DATAIN; - mPdpResetCount = 0; - mRecoveryAction = RecoveryAction.REREGISTER; - } else if (sent == 0 && received == 0) { - newActivity = Activity.NONE; - } else { - mSentSinceLastRecv = 0; - newActivity = Activity.NONE; - } + private void updateDataActivity() { + long sent, received; - if (mActivity != newActivity && mIsScreenOn) { - mActivity = newActivity; - mPhone.notifyDataActivity(); - } - } + Activity newActivity; - int watchdogTrigger = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, - NUMBER_SENT_PACKETS_OF_HANG); + TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); + TxRxSum curTxRxSum = new TxRxSum(); + curTxRxSum.updateTxRxSum(); + mTxPkts = curTxRxSum.txPkts; + mRxPkts = curTxRxSum.rxPkts; - if (mSentSinceLastRecv >= watchdogTrigger) { - // we already have NUMBER_SENT_PACKETS sent without ack - if (mNoRecvPollCount == 0) { - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, - mSentSinceLastRecv); - } + if (VDBG) { + log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); + } - int noRecvPollLimit = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT); + if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { + sent = mTxPkts - preTxRxSum.txPkts; + received = mRxPkts - preTxRxSum.rxPkts; - if (mNoRecvPollCount < noRecvPollLimit) { - // It's possible the PDP context went down and we weren't notified. - // Start polling the context list in an attempt to recover. - if (DBG) log("Polling: no DATAIN in a while; polling PDP"); - mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED)); + if (VDBG) log("updateDataActivity: sent=" + sent + " received=" + received); + if ( sent > 0 && received > 0 ) { + newActivity = Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + newActivity = Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + newActivity = Activity.DATAIN; + } else { + newActivity = Activity.NONE; + } - mNoRecvPollCount++; + if (mActivity != newActivity && mIsScreenOn) { + if (VDBG) log("updateDataActivity: newActivity=" + newActivity); + mActivity = newActivity; + mPhone.notifyDataActivity(); + } + } + } - // Slow down the poll interval to let things happen - mNetStatPollPeriod = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, - POLL_NETSTAT_SLOW_MILLIS); - } else { - if (DBG) log("Polling: Sent " + String.valueOf(mSentSinceLastRecv) + - " pkts since last received start recovery process"); - mNoRecvPollCount = 0; - sendMessage(obtainMessage(EVENT_START_RECOVERY)); - } + private Runnable mPollNetStat = new Runnable() + { + @Override + public void run() { + updateDataActivity(); + + if (mIsScreenOn) { + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); } else { - mNoRecvPollCount = 0; - if (mIsScreenOn) { - mNetStatPollPeriod = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); - } else { - mNetStatPollPeriod = Settings.Secure.getInt(mResolver, - Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, - POLL_NETSTAT_SCREEN_OFF_MILLIS); - } + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, + POLL_NETSTAT_SCREEN_OFF_MILLIS); } if (mNetStatPollEnabled) { @@ -1566,6 +1608,41 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } + private void startDataStallAlarm() { + int delayInMs = Settings.Secure.getInt(mResolver, + Settings.Secure.DATA_STALL_ALARM_DELAY_IN_MS, + DATA_STALL_ALARM_DELAY_IN_MS_DEFAULT); + mDataStallAlarmTag += 1; + if (DBG) { + log("startDataStallAlarm: tag=" + mDataStallAlarmTag + + " delay=" + (delayInMs / 1000) + "s"); + } + AlarmManager am = + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); + + Intent intent = new Intent(INTENT_DATA_STALL_ALARM); + intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag); + mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); + } + + private void stopDataStallAlarm() { + AlarmManager am = + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); + + if (DBG) { + log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + + " mDataStallAlarmIntent=" + mDataStallAlarmIntent); + } + mDataStallAlarmTag += 1; + if (mDataStallAlarmIntent != null) { + am.cancel(mDataStallAlarmIntent); + mDataStallAlarmIntent = null; + } + } + private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode, ApnContext apnContext) { if (DBG) log( "notifyNoData: type=" + apnContext.getApnType()); @@ -1930,6 +2007,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { if (DBG) log("onVoiceCallStarted stop polling"); stopNetStatPoll(); + stopDataStallAlarm(); notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); } } @@ -1940,6 +2018,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (isConnected()) { if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { startNetStatPoll(); + startDataStallAlarm(); notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); } else { // clean slate after call end. @@ -2251,11 +2330,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { onPollPdp(); break; - case EVENT_START_NETSTAT_POLL: - startNetStatPoll(); - break; - - case EVENT_START_RECOVERY: + case EVENT_DO_RECOVERY: doRecovery(); break; @@ -2272,6 +2347,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); stopNetStatPoll(); + stopDataStallAlarm(); mIsPsRestricted = true; break; @@ -2284,6 +2360,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mIsPsRestricted = false; if (isConnected()) { startNetStatPoll(); + startDataStallAlarm(); } else { // TODO: Should all PDN states be checked to fail? if (mState == State.FAILED) { |