Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e664d8c authored by Jack Yu's avatar Jack Yu
Browse files

Data call retry refactoring

Moved retry manager from DataConnection to ApnContext.

bug: 22208242
Change-Id: I0baa80e06e6d815643782c2b549460547d0bfef9
parent ec334adf
Loading
Loading
Loading
Loading
+386 −176
Original line number Diff line number Diff line
@@ -16,12 +16,21 @@

package com.android.internal.telephony;

import android.content.Context;
import android.os.Build;
import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.util.Pair;
import android.text.TextUtils;
import android.util.Pair;

import java.util.Random;
import com.android.internal.telephony.dataconnection.ApnSetting;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;

/**
 * Retry manager allows a simple way to declare a series of
@@ -73,9 +82,74 @@ import java.util.ArrayList;
 * {@hide}
 */
public class RetryManager {
    static public final String LOG_TAG = "RetryManager";
    static public final boolean DBG = false;
    static public final boolean VDBG = false;
    public static final String LOG_TAG = "RetryManager";
    public static final boolean DBG = true;
    public static final boolean VDBG = false; // STOPSHIP if true

    /**
     * The default retry configuration for default type APN. See above for the syntax.
     */
    private 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";

    /**
     * Retry configuration for networks other than default type, for example, mms. See above
     * for the syntax.
     */
    private static final String OTHERS_DATA_RETRY_CONFIG =
            "max_retries=3, 5000, 5000, 5000";

    /**
     * The default value (in milliseconds) for delay between APN trying (mInterApnDelay)
     * within the same round
     */
    private static final long DEFAULT_INTER_APN_DELAY = 20000;

    /**
     * The default value (in milliseconds) for delay between APN trying (mFailFastInterApnDelay)
     * within the same round when we are in fail fast mode
     */
    private static final long DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING = 3000;

    /**
     * The value indicating no retry is needed
     */
    public static final long NO_RETRY = -1;

    /**
     * The value indicating modem did not suggest any retry delay
     */
    public static final long NO_SUGGESTED_RETRY_DELAY = -2;

    /**
     * If the modem suggests a retry delay in the data call setup response, we will retry
     * the current APN setting again. However, if the modem keeps suggesting retrying the same
     * APN setting, we'll fall into an infinite loop. Therefore adding a counter to retry up to
     * MAX_SAME_APN_RETRY times can avoid it.
     */
    private static final int MAX_SAME_APN_RETRY = 3;

    /**
     * The delay (in milliseconds) between APN trying within the same round
     */
    private long mInterApnDelay;

    /**
     * The delay (in milliseconds) between APN trying within the same round when we are in
     * fail fast mode
     */
    private long mFailFastInterApnDelay;

    /**
     * Modem suggested delay for retrying the current APN
     */
    private long mModemSuggestedDelay = NO_SUGGESTED_RETRY_DELAY;

    /**
     * The counter for same APN retrying. See MAX_SAME_APN_RETRY for the details.
     */
    private int mSameApnRetryCount = 0;

    /**
     * Retry record with times in milli-seconds
@@ -90,38 +164,69 @@ public class RetryManager {
        int mRandomizationTime;
    }

    /** The array of retry records */
    /**
     * The array of retry records
     */
    private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>();

    /** When true isRetryNeeded() will always return true */
    private boolean mRetryForever;
    private Phone mPhone;

    /**
     * The maximum number of retries to attempt before
     * isRetryNeeded returns false
     * Flag indicating whether retrying forever regardless the maximum retry count mMaxRetryCount
     */
    private int mMaxRetryCount;
    private boolean mRetryForever = false;

    private int mCurMaxRetryCount;
    /**
     * The maximum number of retries to attempt
     */
    private int mMaxRetryCount;

    /** The current number of retries */
    private int mRetryCount;
    /**
     * The current number of retries
     */
    private int mRetryCount = 0;

    /** Random number generator */
    /**
     * Random number generator. The random delay will be added into retry timer to avoid all devices
     * around retrying the APN at the same time.
     */
    private Random mRng = new Random();

    /**
     * Retry manager configuration string. See top of the detailed explanation.
     */
    private String mConfig;

    /** Constructor */
    public RetryManager() {
        if (VDBG) log("constructor");
    /**
     * The list to store APN setting candidates for data call setup. Most of the carriers only have
     * one APN, but few carriers have more than one.
     */
    private ArrayList<ApnSetting> mWaitingApns = null;

    /**
     * Index pointing to the current trying APN from mWaitingApns
     */
    private int mCurrentApnIndex = -1;

    /**
     * Apn context type. Could be "default, "mms", "supl", etc...
     */
    private String mApnType;

    /**
     * Retry manager constructor
     * @param phone Phone object
     * @param apnType APN type
     */
    public RetryManager(Phone phone, String apnType) {
        mPhone = phone;
        mApnType = apnType;
    }

    @Override
    public String toString() {
        String ret = "RetryManager: { forever=" + mRetryForever + " maxRetry=" + mMaxRetryCount
                + " curMaxRetry=" + mCurMaxRetryCount + " retry=" + mRetryCount
                + " config={" + mConfig + "} retryArray={";
                + " retry=" + mRetryCount + " config={" + mConfig + "} retryArray={";
        for (RetryRec r : mRetryArray) {
            ret += r.mDelayTime + ":" + r.mRandomizationTime + " ";
        }
@@ -129,45 +234,6 @@ public class RetryManager {
        return ret;
    }

    /**
     * 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 successful
     */
    public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
        Pair<Boolean, Integer> value;

        if (VDBG) 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;
        mCurMaxRetryCount = mMaxRetryCount;

        resetRetryCount();
        mRetryArray.clear();
        mRetryArray.add(new RetryRec(retryTime, randomizationTime));

        return true;
    }

    /**
     * Configure for using string which allow arbitrary
     * sequences of times. See class comments for the
@@ -175,12 +241,16 @@ public class RetryManager {
     *
     * @return true if successful
     */
    public boolean configure(String configStr) {
    private boolean configure(String configStr) {
        // Strip quotes if present.
        if ((configStr.startsWith("\"") && configStr.endsWith("\""))) {
            configStr = configStr.substring(1, configStr.length() - 1);
        }
        if (VDBG) log("configure: '" + configStr + "'");

        // Reset the retry manager since delay, max retry count, etc...will be reset.
        reset();

        if (DBG) log("configure: '" + configStr + "'");
        mConfig = configStr;

        if (!TextUtils.isEmpty(configStr)) {
@@ -188,10 +258,6 @@ public class RetryManager {

            if (VDBG) log("configure: not empty");

            mMaxRetryCount = 0;
            resetRetryCount();
            mRetryArray.clear();

            String strArray[] = configStr.split(",");
            for (int i = 0; i < strArray.length; i++) {
                if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
@@ -248,31 +314,70 @@ public class RetryManager {
                mMaxRetryCount = mRetryArray.size();
                if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
            }
            mCurMaxRetryCount = mMaxRetryCount;
            if (VDBG) log("configure: true");
            return true;
        } else {
            if (VDBG) log("configure: false it's empty");
            return false;
            log("configure: cleared");
        }

        if (VDBG) log("configure: true");
        return true;
    }

    /**
     * Report whether data reconnection should be retried
     *
     * @return {@code true} if the max retries has not been reached. {@code
     *         false} otherwise.
     * Configure the retry manager
     * @param forDefault True if the APN support default type
     */
    public boolean isRetryNeeded() {
        boolean retVal = mRetryForever || (mRetryCount < mCurMaxRetryCount);
        if (DBG) log("isRetryNeeded: " + retVal);
        return retVal;
    private void configureRetry(boolean forDefault) {
        String configString = "";
        try {
            if (Build.IS_DEBUGGABLE) {
                // Using system properties is easier for testing from command line.
                String config = SystemProperties.get("test.data_retry_config");
                if (!TextUtils.isEmpty(config)) {
                    configure(config);
                    return;
                }
            }

            CarrierConfigManager configManager = (CarrierConfigManager)
                    mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
            PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());

            mInterApnDelay = b.getLong(
                    CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG,
                    DEFAULT_INTER_APN_DELAY);
            mFailFastInterApnDelay = b.getLong(
                    CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG,
                    DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING);

            if (forDefault) {
                configString = b.getString(
                        CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING,
                        DEFAULT_DATA_RETRY_CONFIG);
            }
            else {
                configString = b.getString(
                        CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING,
                        OTHERS_DATA_RETRY_CONFIG);
            }
        } catch (NullPointerException ex) {
            log("Failed to read configuration! Use the hardcoded default value.");

            mInterApnDelay = DEFAULT_INTER_APN_DELAY;
            mFailFastInterApnDelay = DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING;
            configString = (forDefault) ? DEFAULT_DATA_RETRY_CONFIG : OTHERS_DATA_RETRY_CONFIG;
        }

        if (VDBG) {
            log("mInterApnDelay = " + mInterApnDelay + ", mFailFastInterApnDelay = " + mFailFastInterApnDelay);
        }

        configure(configString);
    }

    /**
     * Return the timer that should be used to trigger the data reconnection
     */
    public int getRetryTimer() {
    private int getRetryTimer() {
        int index;
        if (mRetryCount < mRetryArray.size()) {
            index = mRetryCount;
@@ -292,154 +397,259 @@ public class RetryManager {
    }

    /**
     * @return retry count
     * Parse an integer validating the value is not negative.
     * @param name Name
     * @param stringValue Value
     * @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) {
            Rlog.e(LOG_TAG, name + " bad value: " + stringValue, e);
            retVal = new Pair<Boolean, Integer>(false, 0);
        }
        if (VDBG) {
            log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
                    + retVal.first + ", " + retVal.second);
        }
        return retVal;
    }

    /**
     * Validate an integer is >= 0 and logs an error if not
     * @param name Name
     * @param value Value
     * @return Pair.first
     */
    public int getRetryCount() {
        if (DBG) log("getRetryCount: " + mRetryCount);
        return mRetryCount;
    private boolean validateNonNegativeInt(String name, int value) {
        boolean retVal;
        if (value < 0) {
            Rlog.e(LOG_TAG, name + " bad value: is < 0");
            retVal = false;
        } else {
            retVal = true;
        }
        if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
        return retVal;
    }

    /**
     * Increase the retry counter, does not change retry forever.
     * Return next random number for the index
     * @param index Retry index
     */
    public void increaseRetryCount() {
        mRetryCount++;
        if (mRetryCount > mCurMaxRetryCount) {
            mRetryCount = mCurMaxRetryCount;
    private int nextRandomizationTime(int index) {
        int randomTime = mRetryArray.get(index).mRandomizationTime;
        if (randomTime == 0) {
            return 0;
        } else {
            return mRng.nextInt(randomTime);
        }
        if (DBG) log("increaseRetryCount: " + mRetryCount);
    }

    /**
     * Set retry count to the specified value
     * Get the next APN setting for data call setup.
     * @return APN setting to try
     */
    public void setRetryCount(int count) {
        mRetryCount = count;
        if (mRetryCount > mCurMaxRetryCount) {
            mRetryCount = mCurMaxRetryCount;
    public ApnSetting getNextApnSetting() {

        if (mWaitingApns == null || mWaitingApns.size() == 0) {
            log("Waiting APN list is null or empty.");
            return null;
        }

        if (mRetryCount < 0) {
            mRetryCount = 0;
        // If the modem had suggested a retry delay, we should retry the current APN again
        // (up to MAX_SAME_APN_RETRY times) instead of getting the next APN setting from
        // our own list.
        if (mModemSuggestedDelay != NO_SUGGESTED_RETRY_DELAY &&
                mSameApnRetryCount < MAX_SAME_APN_RETRY) {
            mSameApnRetryCount++;
            return mWaitingApns.get(mCurrentApnIndex);
        }

        if (DBG) log("setRetryCount: " + mRetryCount);
        mSameApnRetryCount = 0;

        int index = mCurrentApnIndex;
        // Loop through the APN list to find out the index of next non-permanent failed APN.
        while (true) {
            if (++index == mWaitingApns.size()) index = 0;

            // Stop if we find the non-failed APN.
            if (mWaitingApns.get(index).permanentFailed == false) break;

            // If we've already cycled through all the APNs, that means there is no APN we can try
            if (index == mCurrentApnIndex) return null;
        }

        mCurrentApnIndex = index;
        return mWaitingApns.get(mCurrentApnIndex);
    }

    /**
     * Set current maximum retry count to the specified value
     * Get the delay for trying the next waiting APN from the list.
     * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter
     *                        delay.
     * @return delay in milliseconds
     */
    public void setCurMaxRetryCount(int count) {
        mCurMaxRetryCount = count;
    public long getDelayForNextApn(boolean failFastEnabled) {

        if (mWaitingApns == null || mWaitingApns.size() == 0) {
            log("Waiting APN list is null or empty.");
            return NO_RETRY;
        }

        // Make sure it's not negative
        if (mCurMaxRetryCount < 0) {
            mCurMaxRetryCount = 0;
        if (mModemSuggestedDelay != NO_SUGGESTED_RETRY_DELAY &&
                mSameApnRetryCount < MAX_SAME_APN_RETRY) {
            // If the modem explicitly suggests a retry delay, we should use it, even in fail fast
            // mode.
            return mModemSuggestedDelay;
        }

        // Make sure mRetryCount is within range
        setRetryCount(mRetryCount);
        // In order to determine the delay to try next APN, we need to peek the next available APN.
        // Case 1 - If we will start the next round of APN trying,
        //    we use the exponential-growth delay. (e.g. 5s, 10s, 30s...etc.)
        // Case 2 - If we are still within the same round of APN trying,
        //    we use the fixed standard delay between APNs. (e.g. 20s)

        if (DBG) log("setCurMaxRetryCount: " + mCurMaxRetryCount);
        int index = mCurrentApnIndex;
        while (true) {
            if (++index >= mWaitingApns.size()) index = 0;

            // Stop if we find the non-failed APN.
            if (mWaitingApns.get(index).permanentFailed == false) break;

            // If we've already cycled through all the APNs, that means all APNs have
            // permanently failed
            if (index == mCurrentApnIndex) return NO_RETRY;
        }

    /**
     * Restore CurMaxRetryCount
     */
    public void restoreCurMaxRetryCount() {
        mCurMaxRetryCount = mMaxRetryCount;
        long delay;
        if (index <= mCurrentApnIndex) {
            // Case 1, if the next APN is in the next round.
            if (!mRetryForever && mRetryCount + 1 > mMaxRetryCount) {
                log("Reached maximum retry count " + mMaxRetryCount + ".");
                return NO_RETRY;
            }
            delay = getRetryTimer();
            ++mRetryCount;
        } else {
            // Case 2, if the next APN is still in the same round.
            delay = mInterApnDelay;
        }

        if (failFastEnabled && delay > mFailFastInterApnDelay) {
            // If we enable fail fast mode, and the delay we got is longer than
            // fail-fast delay (mFailFastInterApnDelay), use the fail-fast delay. If the delay we calculated
            // is already shorter than fail-fast delay, then ignore fail-fast delay.
            delay = mFailFastInterApnDelay;
        }

        // Make sure mRetryCount is within range
        setRetryCount(mRetryCount);
        return delay;
    }

    /**
     * Set retry forever to the specified value
     */
    public void setRetryForever(boolean retryForever) {
        mRetryForever = retryForever;
        if (DBG) log("setRetryForever: " + mRetryForever);
     * Mark the APN setting permanently failed.
     * @param apn APN setting to be marked as permanently failed
     * */
    public void markApnPermanentFailed(ApnSetting apn) {
        if (apn != null) {
            apn.permanentFailed = true;
        }
    }

    /**
     * Clear the data-retry counter
     * Reset the retry manager.
     */
    public void resetRetryCount() {
    private void reset() {
        mMaxRetryCount = 0;
        mRetryCount = 0;
        if (DBG) log("resetRetryCount: " + mRetryCount);
        mCurrentApnIndex = -1;
        mSameApnRetryCount = 0;
        mModemSuggestedDelay = NO_SUGGESTED_RETRY_DELAY;
        mRetryArray.clear();
    }

    /**
     * Retry forever using last timeout time.
     * Set waiting APNs for retrying in case needed.
     * @param waitingApns Waiting APN list
     */
    public void retryForeverUsingLastTimeout() {
        mRetryCount = mCurMaxRetryCount;
        mRetryForever = true;
        if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount);
    public void setWaitingApns(ArrayList<ApnSetting> waitingApns) {

        if (waitingApns == null) {
            log("No waiting APNs provided");
            return;
        }

    /**
     * @return true if retrying forever
     */
    public boolean isRetryForever() {
        if (DBG) log("isRetryForever: " + mRetryForever);
        return mRetryForever;
        mWaitingApns = waitingApns;

        // Since we replace the entire waiting APN list, we need to re-config this retry manager.
        configureRetry(mApnType.equals(PhoneConstants.APN_TYPE_DEFAULT));

        for (ApnSetting apn : mWaitingApns) {
            apn.permanentFailed = false;
        }

    /**
     * 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) {
            Rlog.e(LOG_TAG, name + " bad value: " + stringValue, e);
            retVal = new Pair<Boolean, Integer>(false, 0);
        log("Setting " + mWaitingApns.size() + " waiting APNs.");

        if (VDBG) {
            for (int i = 0; i < mWaitingApns.size(); i++) {
                log("  [" + i + "]:" + mWaitingApns.get(i));
            }
        }
        if (VDBG) 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
     * Get the list of waiting APNs.
     * @return the list of waiting APNs
     */
    private boolean validateNonNegativeInt(String name, int value) {
        boolean retVal;
        if (value < 0) {
            Rlog.e(LOG_TAG, name + " bad value: is < 0");
            retVal = false;
        } else {
            retVal = true;
    public ArrayList<ApnSetting> getWaitingApns() {
        return mWaitingApns;
    }
        if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
        return retVal;

    /**
     * Save the modem suggested delay for retrying the current APN.
     * This method is called when we get the suggested delay from RIL.
     * @param delay The delay in milliseconds
     */
    public void setModemSuggestedDelay(long delay) {
        mModemSuggestedDelay = delay;
    }

    /**
     * Return next random number for the index
     * Get the delay between APN setting trying. This is the fixed delay used for APN setting trying
     * within the same round, comparing to the exponential delay used for different rounds.
     * @param failFastEnabled True if fail fast mode enabled, which a shorter delay will be used
     * @return The delay in milliseconds
     */
    private int nextRandomizationTime(int index) {
        int randomTime = mRetryArray.get(index).mRandomizationTime;
        if (randomTime == 0) {
            return 0;
        } else {
            return mRng.nextInt(randomTime);
    public long getInterApnDelay(boolean failFastEnabled) {
        return (failFastEnabled) ? mFailFastInterApnDelay : mInterApnDelay;
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("  RetryManager");
        pw.println("  ***************************************");

        pw.println("    config = " + mConfig);
        pw.println("    mApnType = " + mApnType);
        pw.println("    mCurrentApnIndex = " + mCurrentApnIndex);
        pw.println("    mRetryCount = " + mRetryCount);
        pw.println("    mMaxRetryCount = " + mMaxRetryCount);
        pw.println("    mSameApnRetryCount = " + mSameApnRetryCount);
        pw.println("    mModemSuggestedDelay = " + mModemSuggestedDelay);

        pw.println("    APN list: ");
        for (int i = 0; i < mWaitingApns.size(); i++) {
            pw.println("      [" + i + "]=" + mWaitingApns.get(i));
        }

        pw.println("  ***************************************");
        pw.flush();
    }

    private void log(String s) {
        Rlog.d(LOG_TAG, "[RM] " + s);
        Rlog.d(LOG_TAG, "[" + mApnType + "] " + s);
    }
}
+146 −48

File changed.

Preview size limit exceeded, changes collapsed.

+46 −2

File changed.File mode changed from 100755 to 100644.

Preview size limit exceeded, changes collapsed.

+50 −347

File changed.

Preview size limit exceeded, changes collapsed.

+5 −9
Original line number Diff line number Diff line
@@ -361,22 +361,18 @@ public class DcAsyncChannel extends AsyncChannel {
     * as GSM networks.
     *
     * @param apnContext is the Access Point Name to bring up a connection to
     * @param initialMaxRetry the number of retires for initial bringup.
     * @param profileId for the conneciton
     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
     *        With AsyncResult.userObj set to the original msg.obj,
     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
     */
    public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
            int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg,
            int connectionGeneration) {
    public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
                        Message onCompletedMsg, int connectionGeneration) {
        if (DBG) {
            log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
                + " onCompletedMsg=" + onCompletedMsg);
            log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
        }
        sendMessage(DataConnection.EVENT_CONNECT,
                    new ConnectionParams(apnContext, initialMaxRetry, profileId,
                            rilRadioTechnology, retryWhenSSChange, onCompletedMsg,
                new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
                        connectionGeneration));
    }

Loading