diff options
6 files changed, 642 insertions, 51 deletions
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index c074cb8..a3f1ad8 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -96,10 +96,11 @@ public abstract class DataConnectionTracker extends Handler { public static final int EVENT_CLEAN_UP_CONNECTION = 34; //***** Constants - protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; - /** Cap out with 30 min retry interval. */ - protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000; + /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ + protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," + + "5000,10000,20000,40000,80000:5000,160000:5000," + + "320000:5000,640000:5000,1280000:5000,1800000:5000"; /** Slow poll when attempting connection recovery. */ protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java new file mode 100644 index 0000000..242b2cd --- /dev/null +++ b/telephony/java/com/android/internal/telephony/RetryManager.java @@ -0,0 +1,383 @@ +/** + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.util.Log; +import android.util.Pair; +import android.text.TextUtils; + +import java.util.Random; +import java.util.ArrayList; + +/** + * Retry manager allows a simple way to declare a series of + * retires timeouts. After creating a RetryManager the configure + * method is used to define the sequence. A simple linear series + * may be initialized using configure with three integer parameters + * The other configure method allows a series to be declared using + * a string. + *<p> + * The format of the configuration string is a series of parameters + * separated by a comma. There are two name value pair parameters plus a series + * of delay times. The units of of these delay times is unspecified. + * The name value pairs which may be specified are: + *<ul> + *<li>max_retries=<value> + *<li>default_randomizationTime=<value> + *</ul> + *<p> + * max_retries is the number of times that incrementRetryCount + * maybe called before isRetryNeeded will return false. + * + * default_randomizationTime will be used as the randomizationTime + * for delay times which have no supplied randomizationTime. If + * default_randomizationTime is not defined it defaults to 0. + *<p> + * The other parameters define The series of delay times and each + * may have an optional randomization value separated from the + * delay time by a colon. + *<p> + * Examples: + * <ul> + * <li>3 retires with no randomization value which means its 0: + * <ul><li><code>"1000, 2000, 3000"</code></ul> + * + * <li>10 retires with a 500 default randomization value for each and + * the 4..10 retries all using 3000 as the delay: + * <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul> + * + * <li>4 retires with a 100ms default randomization value for the first 2 values and + * the other two having specified values of 500ms: + * <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul> + * </ul> + * + * {@hide} + */ +public class RetryManager { + static public final String LOG_TAG = "RetryManager"; + static public final boolean DBG = false; + static public final int RETRYIES_NOT_STARTED = 0; + static public final int RETRYIES_ON_GOING = 1; + static public final int RETRYIES_COMPLETED = 2; + + /** + * Retry record with times in milli-seconds + */ + private static class RetryRec { + RetryRec(int delayTime, int randomizationTime) { + mDelayTime = delayTime; + mRandomizationTime = randomizationTime; + } + + int mDelayTime; + int mRandomizationTime; + } + + /** The array of retry records */ + private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>(); + + /** When true isRetryNeeded() will always return true */ + private boolean mRetryForever; + + /** + * The maximum number of retries to attempt before + * isRetryNeeded returns false + */ + private int mMaxRetryCount; + + /** The current number of retires */ + private int mRetryCount; + + /** Random number generator */ + private Random rng = new Random(); + + /** Constructor */ + public RetryManager() { + if (DBG) log("constructor"); + } + + /** + * Configure for a simple linear sequence of times plus + * a random value. + * + * @param maxRetryCount is the maximum number of retries + * before isRetryNeeded returns false. + * @param retryTime is a time that will be returned by getRetryTime. + * @param randomizationTime a random value between 0 and + * randomizationTime will be added to retryTime. this + * parameter may be 0. + * @return true if successfull + */ + public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) { + Pair<Boolean, Integer> value; + + if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime); + + if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) { + return false; + } + + if (!validateNonNegativeInt("retryTime", retryTime)) { + return false; + } + + if (!validateNonNegativeInt("randomizationTime", randomizationTime)) { + return false; + } + + mMaxRetryCount = maxRetryCount; + resetRetryCount(); + mRetryArray.clear(); + mRetryArray.add(new RetryRec(retryTime, randomizationTime)); + + return true; + } + + /** + * Configure for using string which allow arbitary + * sequences of times. See class comments for the + * string format. + * + * @return true if successfull + */ + public boolean configure(String configStr) { + if (DBG) log("configure: '" + configStr + "'"); + + if (!TextUtils.isEmpty(configStr)) { + int defaultRandomization = 0; + + if (DBG) log("configure: not empty"); + + mMaxRetryCount = 0; + resetRetryCount(); + mRetryArray.clear(); + + String strArray[] = configStr.split(","); + for (int i = 0; i < strArray.length; i++) { + if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'"); + Pair<Boolean, Integer> value; + String splitStr[] = strArray[i].split("=", 2); + splitStr[0] = splitStr[0].trim(); + if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'"); + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + if (TextUtils.equals(splitStr[0], "default_randomization")) { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + defaultRandomization = value.second; + } else if (TextUtils.equals(splitStr[0], "max_retries")) { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + mMaxRetryCount = value.second; + } else { + Log.e(LOG_TAG, "Unrecognized configuration name value pair: " + + strArray[i]); + return false; + } + } else { + /** + * Assume a retry time with an optional randomization value + * following a ":" + */ + splitStr = strArray[i].split(":", 2); + splitStr[0] = splitStr[0].trim(); + RetryRec rr = new RetryRec(0, 0); + value = parseNonNegativeInt("delayTime", splitStr[0]); + if (!value.first) return false; + rr.mDelayTime = value.second; + + // Check if optional randomization value present + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + value = parseNonNegativeInt("randomizationTime", splitStr[1]); + if (!value.first) return false; + rr.mRandomizationTime = value.second; + } else { + rr.mRandomizationTime = defaultRandomization; + } + mRetryArray.add(rr); + } + } + if (mRetryArray.size() > mMaxRetryCount) { + mMaxRetryCount = mRetryArray.size(); + if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount); + } + if (DBG) log("configure: true"); + return true; + } else { + if (DBG) log("configure: false it's empty"); + return false; + } + } + + /** + * Report whether data reconnection should be retried + * + * @return {@code true} if the max retires has not been reached. {@code + * false} otherwise. + */ + public boolean isRetryNeeded() { + boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount); + if (DBG) log("isRetryNeeded: " + retVal); + return retVal; + } + + /** + * Return the timer that should be used to trigger the data reconnection + */ + public int getRetryTimer() { + int index; + if (mRetryCount < mRetryArray.size()) { + index = mRetryCount; + } else { + index = mRetryArray.size() - 1; + } + + int retVal; + if ((index >= 0) && (index < mRetryArray.size())) { + retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index); + } else { + retVal = 0; + } + + if (DBG) log("getRetryTimer: " + retVal); + return retVal; + } + + /** + * @return retry count + */ + public int getRetryCount() { + if (DBG) log("getRetryCount: " + mRetryCount); + return mRetryCount; + } + + /** + * Increase the retry counter, does not change retry forever. + */ + public void increaseRetryCount() { + mRetryCount++; + if (mRetryCount > mMaxRetryCount) { + mRetryCount = mMaxRetryCount; + } + if (DBG) log("increseRetryCount: " + mRetryCount); + } + + /** + * Set retry count to the specified value + * and turns off retrying forever. + */ + public void setRetryCount(int count) { + mRetryCount = count; + if (mRetryCount > mMaxRetryCount) { + mRetryCount = mMaxRetryCount; + } + + if (mRetryCount < 0) { + mRetryCount = 0; + } + + mRetryForever = false; + if (DBG) log("setRetryCount: " + mRetryCount); + } + + /** + * Reset network re-registration indicator and clear the data-retry counter + * and turns off retrying forever. + */ + public void resetRetryCount() { + mRetryCount = 0; + mRetryForever = false; + if (DBG) log("resetRetryCount: " + mRetryCount); + } + + /** + * Retry forever using last timeout time. + */ + public void retryForeverUsingLastTimeout() { + mRetryCount = mMaxRetryCount; + mRetryForever = true; + if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount); + } + + /** + * @return true if retrying forever + */ + public boolean isRetryForever() { + if (DBG) log("isRetryForever: " + mRetryForever); + return mRetryForever; + } + + /** + * Parse an integer validating the value is not negative. + * + * @param name + * @param stringValue + * @return Pair.first == true if stringValue an integer >= 0 + */ + private Pair<Boolean, Integer> parseNonNegativeInt(String name, String stringValue) { + int value; + Pair<Boolean, Integer> retVal; + try { + value = Integer.parseInt(stringValue); + retVal = new Pair<Boolean, Integer>(validateNonNegativeInt(name, value), value); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, name + " bad value: " + stringValue, e); + retVal = new Pair<Boolean, Integer>(false, 0); + } + if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", " + + retVal.first + ", " + retVal.second); + return retVal; + } + + /** + * Validate an integer is >= 0 and logs an error if not + * + * @param name + * @param value + * @return Pair.first + */ + private boolean validateNonNegativeInt(String name, int value) { + boolean retVal; + if (value < 0) { + Log.e(LOG_TAG, name + " bad value: is < 0"); + retVal = false; + } else { + retVal = true; + } + if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal); + return retVal; + } + + /** + * Return next random number for the index + */ + private int nextRandomizationTime(int index) { + int randomTime = mRetryArray.get(index).mRandomizationTime; + if (randomTime == 0) { + return 0; + } else { + return rng.nextInt(randomTime); + } + } + + private void log(String s) { + Log.d(LOG_TAG, s); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index c3818f5..38bc24d 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -31,6 +31,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Checkin; import android.telephony.ServiceState; @@ -45,6 +46,7 @@ import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyEventLog; @@ -61,8 +63,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Indicates baseband will not auto-attach private boolean noAutoAttach = false; - long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - private boolean mReregisterOnReconnectFailure = false; private boolean mIsScreenOn = true; //useful for debugging @@ -76,6 +76,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** Currently active CdmaDataConnection */ private CdmaDataConnection mActiveDataConnection; + /** Manage the behavior of data retry after failure */ + private final RetryManager mRetryMgr = new RetryManager(); + /** Defined cdma connection profiles */ private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0; private static final int EXTERNAL_NETWORK_NUM_TYPES = 1; @@ -183,10 +186,19 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] = !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false); noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + + if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) { + if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + mRetryMgr.configure(20, 2000, 1000); + } + } } public void dispose() { - //Unregister from all events + // Unregister from all events phone.mCM.unregisterForAvailable(this); phone.mCM.unregisterForOffOrNotAvailable(this); mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this); @@ -459,9 +471,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { setState(State.CONNECTED); phone.notifyDataConnection(reason); startNetStatPoll(); - // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); } private void resetPollStats() { @@ -617,21 +627,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { - if (mReregisterOnReconnectFailure) { - // We have already tried to re-register to the network. - // This might be a problem with the data network. - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; - } else { - // Try to Re-register to the network. - Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); - mReregisterOnReconnectFailure = true; - mCdmaPhone.mSST.reRegisterNetwork(null); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - return; - } - } - + /** + * For now With CDMA we never try to reconnect on + * error and instead just continue to retry + * at the last time until the state is changed. + * TODO: Make this configurable? + */ + int nextReconnectDelay = mRetryMgr.getRetryTimer(); Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -645,8 +647,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); - // double it for next time - nextReconnectDelay *= 2; + mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " @@ -723,10 +724,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * @override com.android.internal.telephony.DataConnectionTracker */ protected void onRadioOffOrNotAvailable() { - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); if (phone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator @@ -802,9 +800,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { resetPollStats(); } } else { - // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); } @@ -840,7 +836,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); int bsid = (loc != null) ? loc.getBaseStationId() : -1; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index c33d4b6..8b3529f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -52,6 +52,7 @@ import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.TelephonyEventLog; import com.android.internal.telephony.DataConnection.FailCause; @@ -85,7 +86,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { INetStatService netstat; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; - long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; @@ -95,6 +96,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private int mPdpResetCount = 0; private boolean mIsScreenOn = true; + private final RetryManager mRetryMgr = new RetryManager(); + + /** Delay between APN attempts */ + protected static final int APN_DELAY_MILLIS = 5000; + //useful for debugging boolean failNextConnect = false; @@ -247,6 +253,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false); noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; + + if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { + if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + mRetryMgr.configure(20, 2000, 1000); + } + } } public void dispose() { @@ -558,7 +573,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); } trySetupData(Phone.REASON_GPRS_ATTACHED); } @@ -808,7 +823,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); if (!isConnected) { // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; trySetupData(Phone.REASON_APN_CHANGED); } @@ -889,7 +904,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { phone.notifyDataConnection(reason); startNetStatPoll(); // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; } @@ -1175,20 +1190,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { + if (!mRetryMgr.isRetryNeeded()) { if (mReregisterOnReconnectFailure) { - // We have already tried to re-register to the network. - // This might be a problem with the data network. - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; + // We've re-registerd once now just retry forever. + mRetryMgr.retryForeverUsingLastTimeout(); } else { - // Try to Re-register to the network. + // Try to re-register to the network. Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); mReregisterOnReconnectFailure = true; mGsmPhone.mSST.reRegisterNetwork(null); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); return; } } + + int nextReconnectDelay = mRetryMgr.getRetryTimer(); Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1202,8 +1218,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); - // double it for next time - nextReconnectDelay *= 2; + mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " @@ -1276,7 +1291,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void onRadioOffOrNotAvailable() { // Make sure our reconnect delay starts at the initial value // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; if (phone.getSimulatedRadioControl() != null) { @@ -1361,8 +1376,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.SCANNING); // Wait a bit before trying the next APN, so that // we're not tying up the RIL command channel - sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), - RECONNECT_DELAY_INITIAL_MILLIS); + sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS); } } } @@ -1407,7 +1421,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } else { // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); @@ -1684,7 +1698,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; } trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java index b4fb324..fdfafe1 100644 --- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java +++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java @@ -47,6 +47,7 @@ public class TelephonyTests { suite.addTestSuite(SimUtilsTest.class); suite.addTestSuite(SimPhoneBookTest.class); suite.addTestSuite(SimSmsTest.class); + suite.addTestSuite(TelephonyUtilsTest.class); return suite; } diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java new file mode 100644 index 0000000..e4cf1e8 --- /dev/null +++ b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java @@ -0,0 +1,196 @@ +/** + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.RetryManager; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class TelephonyUtilsTest extends TestCase { + + /** + * After first creating the RetryManager + * isRetryNeeded should be false and the time 0 + */ + @SmallTest + public void testRetryManagerEmpty() throws Exception { + RetryManager rm = new RetryManager(); + + assertEquals(0, rm.getRetryCount()); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(123); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryForever()); + assertTrue(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(2); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + } + + /** + * A simple test and that randomization is doing something. + */ + @SmallTest + public void testRetryManagerSimplest() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(1, 500, 10)); + int loops = 10; + int count = 0; + for (int i = 0; i < loops; i++) { + assertTrue(rm.isRetryNeeded()); + int time = rm.getRetryTimer(); + assertTrue((time >= 500) && (time < 600)); + if (time == 500) { + count++; + } + } + assertFalse(count == loops); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + rm.setRetryCount(0); + assertTrue(rm.isRetryNeeded()); + } + + /** + * Test multiple values using simple configuration. + */ + @SmallTest + public void testRetryManagerSimple() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(3, 1000, 0)); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + assertEquals(rm.getRetryTimer(), 1000); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + } + + /** + * Test string configuration, simplest + */ + @SmallTest + public void testRetryManageSimpleString() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure("101")); + assertTrue(rm.isRetryNeeded()); + assertEquals(101, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test string configuration using all options. + */ + @SmallTest + public void testRetryManageString() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure("max_retries=4," + + "default_randomization=100,1000, 2000 :200 , 3000")); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 1000) && (time < 1100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 2000) && (time < 2200)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test string configuration using all options. + */ + @SmallTest + public void testRetryManageForever() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure("1000, 2000, 3000")); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + assertEquals(3, rm.getRetryCount()); + assertEquals(3000, rm.getRetryTimer()); + + rm.setRetryCount(1); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(1, rm.getRetryCount()); + assertEquals(2000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + rm.resetRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + } +} |