Home | History | Annotate | Download | only in dataconnection
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.dataconnection;
     18 
     19 
     20 import com.android.internal.telephony.CommandException;
     21 import com.android.internal.telephony.DctConstants;
     22 import com.android.internal.telephony.Phone;
     23 import com.android.internal.telephony.PhoneBase;
     24 import com.android.internal.telephony.PhoneConstants;
     25 import com.android.internal.telephony.RILConstants;
     26 import com.android.internal.telephony.RetryManager;
     27 import com.android.internal.util.AsyncChannel;
     28 import com.android.internal.util.Protocol;
     29 import com.android.internal.util.State;
     30 import com.android.internal.util.StateMachine;
     31 
     32 import android.app.PendingIntent;
     33 import android.content.Context;
     34 import android.net.ConnectivityManager;
     35 import android.net.LinkProperties;
     36 import android.net.NetworkAgent;
     37 import android.net.NetworkCapabilities;
     38 import android.net.NetworkInfo;
     39 import android.net.ProxyInfo;
     40 import android.os.AsyncResult;
     41 import android.os.Build;
     42 import android.os.Looper;
     43 import android.os.Message;
     44 import android.os.Messenger;
     45 import android.os.SystemClock;
     46 import android.os.SystemProperties;
     47 import android.telephony.Rlog;
     48 import android.telephony.ServiceState;
     49 import android.telephony.TelephonyManager;
     50 import android.text.TextUtils;
     51 import android.util.Pair;
     52 import android.util.Patterns;
     53 import android.util.TimeUtils;
     54 
     55 import java.io.FileDescriptor;
     56 import java.io.PrintWriter;
     57 import java.util.ArrayList;
     58 import java.util.List;
     59 import java.util.Locale;
     60 import java.util.concurrent.atomic.AtomicInteger;
     61 
     62 import java.net.InetAddress;
     63 import java.util.Collection;
     64 
     65 /**
     66  * {@hide}
     67  *
     68  * DataConnection StateMachine.
     69  *
     70  * This a class for representing a single data connection, with instances of this
     71  * class representing a connection via the cellular network. There may be multiple
     72  * data connections and all of them are managed by the <code>DataConnectionTracker</code>.
     73  *
     74  * A recent change is to move retry handling into this class, with that change the
     75  * old retry manager is now used internally rather than exposed to the DCT. Also,
     76  * bringUp now has an initialRetry which is used limit the number of retries
     77  * during the initial bring up of the connection. After the connection becomes active
     78  * the current max retry is restored to the configured value.
     79  *
     80  * NOTE: All DataConnection objects must be running on the same looper, which is the default
     81  * as the coordinator has members which are used without synchronization.
     82  */
     83 public final class DataConnection extends StateMachine {
     84     private static final boolean DBG = true;
     85     private static final boolean VDBG = true;
     86 
     87     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
     88     private static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
     89         + "5000,10000,20000,40000,80000:5000,160000:5000,"
     90         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
     91 
     92     /** Retry configuration for secondary networks: 4 tries in 20 sec */
     93     private static final String SECONDARY_DATA_RETRY_CONFIG =
     94             "max_retries=3, 5000, 5000, 5000";
     95 
     96     private static final String NETWORK_TYPE = "MOBILE";
     97 
     98     // The data connection controller
     99     private DcController mDcController;
    100 
    101     // The Tester for failing all bringup's
    102     private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
    103 
    104     private static AtomicInteger mInstanceNumber = new AtomicInteger(0);
    105     private AsyncChannel mAc;
    106 
    107     // Utilities for the DataConnection
    108     private DcRetryAlarmController mDcRetryAlarmController;
    109 
    110     // The DCT that's talking to us, we only support one!
    111     private DcTrackerBase mDct = null;
    112 
    113     protected String[] mPcscfAddr;
    114 
    115     /**
    116      * Used internally for saving connecting parameters.
    117      */
    118     static class ConnectionParams {
    119         int mTag;
    120         ApnContext mApnContext;
    121         int mInitialMaxRetry;
    122         int mProfileId;
    123         int mRilRat;
    124         boolean mRetryWhenSSChange;
    125         Message mOnCompletedMsg;
    126 
    127         ConnectionParams(ApnContext apnContext, int initialMaxRetry, int profileId,
    128                 int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
    129             mApnContext = apnContext;
    130             mInitialMaxRetry = initialMaxRetry;
    131             mProfileId = profileId;
    132             mRilRat = rilRadioTechnology;
    133             mRetryWhenSSChange = retryWhenSSChange;
    134             mOnCompletedMsg = onCompletedMsg;
    135         }
    136 
    137         @Override
    138         public String toString() {
    139             return "{mTag=" + mTag + " mApnContext=" + mApnContext
    140                     + " mInitialMaxRetry=" + mInitialMaxRetry + " mProfileId=" + mProfileId
    141                     + " mRat=" + mRilRat
    142                     + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
    143         }
    144     }
    145 
    146     /**
    147      * Used internally for saving disconnecting parameters.
    148      */
    149     static class DisconnectParams {
    150         int mTag;
    151         ApnContext mApnContext;
    152         String mReason;
    153         Message mOnCompletedMsg;
    154 
    155         DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
    156             mApnContext = apnContext;
    157             mReason = reason;
    158             mOnCompletedMsg = onCompletedMsg;
    159         }
    160 
    161         @Override
    162         public String toString() {
    163             return "{mTag=" + mTag + " mApnContext=" + mApnContext
    164                     + " mReason=" + mReason
    165                     + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
    166         }
    167     }
    168 
    169     private ApnSetting mApnSetting;
    170     private ConnectionParams mConnectionParams;
    171     private DisconnectParams mDisconnectParams;
    172     private DcFailCause mDcFailCause;
    173 
    174     private PhoneBase mPhone;
    175     private LinkProperties mLinkProperties = new LinkProperties();
    176     private long mCreateTime;
    177     private long mLastFailTime;
    178     private DcFailCause mLastFailCause;
    179     private static final String NULL_IP = "0.0.0.0";
    180     private Object mUserData;
    181     private int mRilRat = Integer.MAX_VALUE;
    182     private int mDataRegState = Integer.MAX_VALUE;
    183     private NetworkInfo mNetworkInfo;
    184     private NetworkAgent mNetworkAgent;
    185 
    186     //***** Package visible variables
    187     int mTag;
    188     int mCid;
    189     List<ApnContext> mApnContexts = null;
    190     PendingIntent mReconnectIntent = null;
    191     RetryManager mRetryManager = new RetryManager();
    192 
    193 
    194     // ***** Event codes for driving the state machine, package visible for Dcc
    195     static final int BASE = Protocol.BASE_DATA_CONNECTION;
    196     static final int EVENT_CONNECT = BASE + 0;
    197     static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
    198     static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
    199     static final int EVENT_DEACTIVATE_DONE = BASE + 3;
    200     static final int EVENT_DISCONNECT = BASE + 4;
    201     static final int EVENT_RIL_CONNECTED = BASE + 5;
    202     static final int EVENT_DISCONNECT_ALL = BASE + 6;
    203     static final int EVENT_DATA_STATE_CHANGED = BASE + 7;
    204     static final int EVENT_TEAR_DOWN_NOW = BASE + 8;
    205     static final int EVENT_LOST_CONNECTION = BASE + 9;
    206     static final int EVENT_RETRY_CONNECTION = BASE + 10;
    207     static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11;
    208     static final int EVENT_DATA_CONNECTION_ROAM_ON = BASE + 12;
    209     static final int EVENT_DATA_CONNECTION_ROAM_OFF = BASE + 13;
    210 
    211     private static final int CMD_TO_STRING_COUNT = EVENT_DATA_CONNECTION_ROAM_OFF - BASE + 1;
    212     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    213     static {
    214         sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
    215         sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
    216                 "EVENT_SETUP_DATA_CONNECTION_DONE";
    217         sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
    218         sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
    219         sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
    220         sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
    221         sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
    222         sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED";
    223         sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW";
    224         sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION";
    225         sCmdToString[EVENT_RETRY_CONNECTION - BASE] = "EVENT_RETRY_CONNECTION";
    226         sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] =
    227                 "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED";
    228         sCmdToString[EVENT_DATA_CONNECTION_ROAM_ON - BASE] = "EVENT_DATA_CONNECTION_ROAM_ON";
    229         sCmdToString[EVENT_DATA_CONNECTION_ROAM_OFF - BASE] = "EVENT_DATA_CONNECTION_ROAM_OFF";
    230     }
    231     // Convert cmd to string or null if unknown
    232     static String cmdToString(int cmd) {
    233         String value;
    234         cmd -= BASE;
    235         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
    236             value = sCmdToString[cmd];
    237         } else {
    238             value = DcAsyncChannel.cmdToString(cmd + BASE);
    239         }
    240         if (value == null) {
    241             value = "0x" + Integer.toHexString(cmd + BASE);
    242         }
    243         return value;
    244     }
    245 
    246     /**
    247      * Create the connection object
    248      *
    249      * @param phone the Phone
    250      * @param id the connection id
    251      * @return DataConnection that was created.
    252      */
    253     static DataConnection makeDataConnection(PhoneBase phone, int id,
    254             DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
    255             DcController dcc) {
    256         DataConnection dc = new DataConnection(phone,
    257                 "DC-" + mInstanceNumber.incrementAndGet(), id, dct, failBringUpAll, dcc);
    258         dc.start();
    259         if (DBG) dc.log("Made " + dc.getName());
    260         return dc;
    261     }
    262 
    263     void dispose() {
    264         log("dispose: call quiteNow()");
    265         quitNow();
    266     }
    267 
    268     /* Getter functions */
    269 
    270     NetworkCapabilities getCopyNetworkCapabilities() {
    271         return makeNetworkCapabilities();
    272     }
    273 
    274     LinkProperties getCopyLinkProperties() {
    275         return new LinkProperties(mLinkProperties);
    276     }
    277 
    278     boolean getIsInactive() {
    279         return getCurrentState() == mInactiveState;
    280     }
    281 
    282     int getCid() {
    283         return mCid;
    284     }
    285 
    286     ApnSetting getApnSetting() {
    287         return mApnSetting;
    288     }
    289 
    290     void setLinkPropertiesHttpProxy(ProxyInfo proxy) {
    291         mLinkProperties.setHttpProxy(proxy);
    292     }
    293 
    294     static class UpdateLinkPropertyResult {
    295         public DataCallResponse.SetupResult setupResult = DataCallResponse.SetupResult.SUCCESS;
    296         public LinkProperties oldLp;
    297         public LinkProperties newLp;
    298         public UpdateLinkPropertyResult(LinkProperties curLp) {
    299             oldLp = curLp;
    300             newLp = curLp;
    301         }
    302     }
    303 
    304     public boolean isIpv4Connected() {
    305         boolean ret = false;
    306         Collection <InetAddress> addresses = mLinkProperties.getAddresses();
    307 
    308         for (InetAddress addr: addresses) {
    309             if (addr instanceof java.net.Inet4Address) {
    310                 java.net.Inet4Address i4addr = (java.net.Inet4Address) addr;
    311                 if (!i4addr.isAnyLocalAddress() && !i4addr.isLinkLocalAddress() &&
    312                         !i4addr.isLoopbackAddress() && !i4addr.isMulticastAddress()) {
    313                     ret = true;
    314                     break;
    315                 }
    316             }
    317         }
    318         return ret;
    319     }
    320 
    321     public boolean isIpv6Connected() {
    322         boolean ret = false;
    323         Collection <InetAddress> addresses = mLinkProperties.getAddresses();
    324 
    325         for (InetAddress addr: addresses) {
    326             if (addr instanceof java.net.Inet6Address) {
    327                 java.net.Inet6Address i6addr = (java.net.Inet6Address) addr;
    328                 if (!i6addr.isAnyLocalAddress() && !i6addr.isLinkLocalAddress() &&
    329                         !i6addr.isLoopbackAddress() && !i6addr.isMulticastAddress()) {
    330                     ret = true;
    331                     break;
    332                 }
    333             }
    334         }
    335         return ret;
    336     }
    337 
    338     UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) {
    339         UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
    340 
    341         if (newState == null) return result;
    342 
    343         DataCallResponse.SetupResult setupResult;
    344         result.newLp = new LinkProperties();
    345 
    346         // set link properties based on data call response
    347         result.setupResult = setLinkProperties(newState, result.newLp);
    348         if (result.setupResult != DataCallResponse.SetupResult.SUCCESS) {
    349             if (DBG) log("updateLinkProperty failed : " + result.setupResult);
    350             return result;
    351         }
    352         // copy HTTP proxy as it is not part DataCallResponse.
    353         result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
    354 
    355         checkSetMtu(mApnSetting, result.newLp);
    356 
    357         mLinkProperties = result.newLp;
    358 
    359         updateTcpBufferSizes(mRilRat);
    360 
    361         if (DBG && (! result.oldLp.equals(result.newLp))) {
    362             log("updateLinkProperty old LP=" + result.oldLp);
    363             log("updateLinkProperty new LP=" + result.newLp);
    364         }
    365 
    366         if (result.newLp.equals(result.oldLp) == false &&
    367                 mNetworkAgent != null) {
    368             mNetworkAgent.sendLinkProperties(mLinkProperties);
    369         }
    370 
    371         return result;
    372     }
    373 
    374     /**
    375      * Read the MTU value from link properties where it can be set from network. In case
    376      * not set by the network, set it again using the mtu szie value defined in the APN
    377      * database for the connected APN
    378      */
    379     private void checkSetMtu(ApnSetting apn, LinkProperties lp) {
    380         if (lp == null) return;
    381 
    382         if (apn == null || lp == null) return;
    383 
    384         if (lp.getMtu() != PhoneConstants.UNSET_MTU) {
    385             if (DBG) log("MTU set by call response to: " + lp.getMtu());
    386             return;
    387         }
    388 
    389         if (apn != null && apn.mtu != PhoneConstants.UNSET_MTU) {
    390             lp.setMtu(apn.mtu);
    391             if (DBG) log("MTU set by APN to: " + apn.mtu);
    392             return;
    393         }
    394 
    395         int mtu = mPhone.getContext().getResources().getInteger(
    396                 com.android.internal.R.integer.config_mobile_mtu);
    397         if (mtu != PhoneConstants.UNSET_MTU) {
    398             lp.setMtu(mtu);
    399             if (DBG) log("MTU set by config resource to: " + mtu);
    400         }
    401     }
    402 
    403     //***** Constructor (NOTE: uses dcc.getHandler() as its Handler)
    404     private DataConnection(PhoneBase phone, String name, int id,
    405                 DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
    406                 DcController dcc) {
    407         super(name, dcc.getHandler());
    408         setLogRecSize(300);
    409         setLogOnlyTransitions(true);
    410         if (DBG) log("DataConnection constructor E");
    411 
    412         mPhone = phone;
    413         mDct = dct;
    414         mDcTesterFailBringUpAll = failBringUpAll;
    415         mDcController = dcc;
    416         mId = id;
    417         mCid = -1;
    418         mDcRetryAlarmController = new DcRetryAlarmController(mPhone, this);
    419         ServiceState ss = mPhone.getServiceState();
    420         mRilRat = ss.getRilDataRadioTechnology();
    421         mDataRegState = mPhone.getServiceState().getDataRegState();
    422         int networkType = ss.getDataNetworkType();
    423         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
    424                 networkType, NETWORK_TYPE, TelephonyManager.getNetworkTypeName(networkType));
    425         mNetworkInfo.setRoaming(ss.getRoaming());
    426         mNetworkInfo.setIsAvailable(true);
    427 
    428         addState(mDefaultState);
    429             addState(mInactiveState, mDefaultState);
    430             addState(mActivatingState, mDefaultState);
    431             addState(mRetryingState, mDefaultState);
    432             addState(mActiveState, mDefaultState);
    433             addState(mDisconnectingState, mDefaultState);
    434             addState(mDisconnectingErrorCreatingConnection, mDefaultState);
    435         setInitialState(mInactiveState);
    436 
    437         mApnContexts = new ArrayList<ApnContext>();
    438         if (DBG) log("DataConnection constructor X");
    439     }
    440 
    441     private String getRetryConfig(boolean forDefault) {
    442         int nt = mPhone.getServiceState().getNetworkType();
    443 
    444         if (Build.IS_DEBUGGABLE) {
    445             String config = SystemProperties.get("test.data_retry_config");
    446             if (! TextUtils.isEmpty(config)) {
    447                 return config;
    448             }
    449         }
    450 
    451         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
    452             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
    453             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
    454             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
    455             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
    456             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
    457             // CDMA variant
    458             return SystemProperties.get("ro.cdma.data_retry_config");
    459         } else {
    460             // Use GSM variant for all others.
    461             if (forDefault) {
    462                 return SystemProperties.get("ro.gsm.data_retry_config");
    463             } else {
    464                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
    465             }
    466         }
    467     }
    468 
    469     private void configureRetry(boolean forDefault) {
    470         String retryConfig = getRetryConfig(forDefault);
    471 
    472         if (!mRetryManager.configure(retryConfig)) {
    473             if (forDefault) {
    474                 if (!mRetryManager.configure(DEFAULT_DATA_RETRY_CONFIG)) {
    475                     // Should never happen, log an error and default to a simple linear sequence.
    476                     loge("configureRetry: Could not configure using " +
    477                             "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
    478                     mRetryManager.configure(5, 2000, 1000);
    479                 }
    480             } else {
    481                 if (!mRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) {
    482                     // Should never happen, log an error and default to a simple sequence.
    483                     loge("configureRetry: Could note configure using " +
    484                             "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
    485                     mRetryManager.configure(5, 2000, 1000);
    486                 }
    487             }
    488         }
    489         if (DBG) {
    490             log("configureRetry: forDefault=" + forDefault + " mRetryManager=" + mRetryManager);
    491         }
    492     }
    493 
    494     /**
    495      * Begin setting up a data connection, calls setupDataCall
    496      * and the ConnectionParams will be returned with the
    497      * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
    498      *
    499      * @param cp is the connection parameters
    500      */
    501     private void onConnect(ConnectionParams cp) {
    502         if (DBG) log("onConnect: carrier='" + mApnSetting.carrier
    503                 + "' APN='" + mApnSetting.apn
    504                 + "' proxy='" + mApnSetting.proxy + "' port='" + mApnSetting.port + "'");
    505 
    506         // Check if we should fake an error.
    507         if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter  > 0) {
    508             DataCallResponse response = new DataCallResponse();
    509             response.version = mPhone.mCi.getRilVersion();
    510             response.status = mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause.getErrorCode();
    511             response.cid = 0;
    512             response.active = 0;
    513             response.type = "";
    514             response.ifname = "";
    515             response.addresses = new String[0];
    516             response.dnses = new String[0];
    517             response.gateways = new String[0];
    518             response.suggestedRetryTime =
    519                     mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime;
    520             response.pcscf = new String[0];
    521             response.mtu = PhoneConstants.UNSET_MTU;
    522 
    523             Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
    524             AsyncResult.forMessage(msg, response, null);
    525             sendMessage(msg);
    526             if (DBG) {
    527                 log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp()
    528                         + " send error response=" + response);
    529             }
    530             mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1;
    531             return;
    532         }
    533 
    534         mCreateTime = -1;
    535         mLastFailTime = -1;
    536         mLastFailCause = DcFailCause.NONE;
    537 
    538         // msg.obj will be returned in AsyncResult.userObj;
    539         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
    540         msg.obj = cp;
    541 
    542         int authType = mApnSetting.authType;
    543         if (authType == -1) {
    544             authType = TextUtils.isEmpty(mApnSetting.user) ? RILConstants.SETUP_DATA_AUTH_NONE
    545                     : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
    546         }
    547 
    548         String protocol;
    549         if (mPhone.getServiceState().getRoaming()) {
    550             protocol = mApnSetting.roamingProtocol;
    551         } else {
    552             protocol = mApnSetting.protocol;
    553         }
    554 
    555         mPhone.mCi.setupDataCall(
    556                 Integer.toString(cp.mRilRat + 2),
    557                 Integer.toString(cp.mProfileId),
    558                 mApnSetting.apn, mApnSetting.user, mApnSetting.password,
    559                 Integer.toString(authType),
    560                 protocol, msg);
    561     }
    562 
    563     /**
    564      * TearDown the data connection when the deactivation is complete a Message with
    565      * msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj
    566      * containing the parameter o.
    567      *
    568      * @param o is the object returned in the AsyncResult.obj.
    569      */
    570     private void tearDownData(Object o) {
    571         int discReason = RILConstants.DEACTIVATE_REASON_NONE;
    572         if ((o != null) && (o instanceof DisconnectParams)) {
    573             DisconnectParams dp = (DisconnectParams)o;
    574 
    575             if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) {
    576                 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
    577             } else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {
    578                 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
    579             }
    580         }
    581         if (mPhone.mCi.getRadioState().isOn()) {
    582             if (DBG) log("tearDownData radio is on, call deactivateDataCall");
    583             mPhone.mCi.deactivateDataCall(mCid, discReason,
    584                     obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));
    585         } else {
    586             if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
    587             AsyncResult ar = new AsyncResult(o, null, null);
    588             sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar));
    589         }
    590     }
    591 
    592     private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) {
    593         mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason,
    594                 mNetworkInfo.getExtraInfo());
    595         for (ApnContext apnContext : mApnContexts) {
    596             if (apnContext == alreadySent) continue;
    597             if (reason != null) apnContext.setReason(reason);
    598             Message msg = mDct.obtainMessage(event, apnContext);
    599             AsyncResult.forMessage(msg);
    600             msg.sendToTarget();
    601         }
    602     }
    603 
    604     private void notifyAllOfConnected(String reason) {
    605         notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason);
    606     }
    607 
    608     private void notifyAllOfDisconnectDcRetrying(String reason) {
    609         notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DC_RETRYING, reason);
    610     }
    611     private void notifyAllDisconnectCompleted(DcFailCause cause) {
    612         notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, cause.toString());
    613     }
    614 
    615 
    616     /**
    617      * Send the connectionCompletedMsg.
    618      *
    619      * @param cp is the ConnectionParams
    620      * @param cause and if no error the cause is DcFailCause.NONE
    621      * @param sendAll is true if all contexts are to be notified
    622      */
    623     private void notifyConnectCompleted(ConnectionParams cp, DcFailCause cause, boolean sendAll) {
    624         ApnContext alreadySent = null;
    625 
    626         if (cp != null && cp.mOnCompletedMsg != null) {
    627             // Get the completed message but only use it once
    628             Message connectionCompletedMsg = cp.mOnCompletedMsg;
    629             cp.mOnCompletedMsg = null;
    630             if (connectionCompletedMsg.obj instanceof ApnContext) {
    631                 alreadySent = (ApnContext)connectionCompletedMsg.obj;
    632             }
    633 
    634             long timeStamp = System.currentTimeMillis();
    635             connectionCompletedMsg.arg1 = mCid;
    636 
    637             if (cause == DcFailCause.NONE) {
    638                 mCreateTime = timeStamp;
    639                 AsyncResult.forMessage(connectionCompletedMsg);
    640             } else {
    641                 mLastFailCause = cause;
    642                 mLastFailTime = timeStamp;
    643 
    644                 // Return message with a Throwable exception to signify an error.
    645                 if (cause == null) cause = DcFailCause.UNKNOWN;
    646                 AsyncResult.forMessage(connectionCompletedMsg, cause,
    647                         new Throwable(cause.toString()));
    648             }
    649             if (DBG) {
    650                 log("notifyConnectCompleted at " + timeStamp + " cause=" + cause
    651                         + " connectionCompletedMsg=" + msgToString(connectionCompletedMsg));
    652             }
    653 
    654             connectionCompletedMsg.sendToTarget();
    655         }
    656         if (sendAll) {
    657             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR,
    658                     cause.toString());
    659         }
    660     }
    661 
    662     /**
    663      * Send ar.userObj if its a message, which is should be back to originator.
    664      *
    665      * @param dp is the DisconnectParams.
    666      */
    667     private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
    668         if (VDBG) log("NotifyDisconnectCompleted");
    669 
    670         ApnContext alreadySent = null;
    671         String reason = null;
    672 
    673         if (dp != null && dp.mOnCompletedMsg != null) {
    674             // Get the completed message but only use it once
    675             Message msg = dp.mOnCompletedMsg;
    676             dp.mOnCompletedMsg = null;
    677             if (msg.obj instanceof ApnContext) {
    678                 alreadySent = (ApnContext)msg.obj;
    679             }
    680             reason = dp.mReason;
    681             if (VDBG) {
    682                 log(String.format("msg=%s msg.obj=%s", msg.toString(),
    683                     ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
    684             }
    685             AsyncResult.forMessage(msg);
    686             msg.sendToTarget();
    687         }
    688         if (sendAll) {
    689             if (reason == null) {
    690                 reason = DcFailCause.UNKNOWN.toString();
    691             }
    692             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason);
    693         }
    694         if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
    695     }
    696 
    697     /*
    698      * **************************************************************************
    699      * Begin Members and methods owned by DataConnectionTracker but stored
    700      * in a DataConnection because there is one per connection.
    701      * **************************************************************************
    702      */
    703 
    704     /*
    705      * The id is owned by DataConnectionTracker.
    706      */
    707     private int mId;
    708 
    709     /**
    710      * Get the DataConnection ID
    711      */
    712     public int getDataConnectionId() {
    713         return mId;
    714     }
    715 
    716     /*
    717      * **************************************************************************
    718      * End members owned by DataConnectionTracker
    719      * **************************************************************************
    720      */
    721 
    722     /**
    723      * Clear all settings called when entering mInactiveState.
    724      */
    725     private void clearSettings() {
    726         if (DBG) log("clearSettings");
    727 
    728         mCreateTime = -1;
    729         mLastFailTime = -1;
    730         mLastFailCause = DcFailCause.NONE;
    731         mCid = -1;
    732 
    733         mPcscfAddr = new String[5];
    734 
    735         mLinkProperties = new LinkProperties();
    736         mApnContexts.clear();
    737         mApnSetting = null;
    738         mDcFailCause = null;
    739     }
    740 
    741     /**
    742      * Process setup completion.
    743      *
    744      * @param ar is the result
    745      * @return SetupResult.
    746      */
    747     private DataCallResponse.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
    748         DataCallResponse response = (DataCallResponse) ar.result;
    749         ConnectionParams cp = (ConnectionParams) ar.userObj;
    750         DataCallResponse.SetupResult result;
    751 
    752         if (cp.mTag != mTag) {
    753             if (DBG) {
    754                 log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag);
    755             }
    756             result = DataCallResponse.SetupResult.ERR_Stale;
    757         } else if (ar.exception != null) {
    758             if (DBG) {
    759                 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
    760                     " response=" + response);
    761             }
    762 
    763             if (ar.exception instanceof CommandException
    764                     && ((CommandException) (ar.exception)).getCommandError()
    765                     == CommandException.Error.RADIO_NOT_AVAILABLE) {
    766                 result = DataCallResponse.SetupResult.ERR_BadCommand;
    767                 result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
    768             } else if ((response == null) || (response.version < 4)) {
    769                 result = DataCallResponse.SetupResult.ERR_GetLastErrorFromRil;
    770             } else {
    771                 result = DataCallResponse.SetupResult.ERR_RilError;
    772                 result.mFailCause = DcFailCause.fromInt(response.status);
    773             }
    774         } else if (response.status != 0) {
    775             result = DataCallResponse.SetupResult.ERR_RilError;
    776             result.mFailCause = DcFailCause.fromInt(response.status);
    777         } else {
    778             if (DBG) log("onSetupConnectionCompleted received DataCallResponse: " + response);
    779             mCid = response.cid;
    780 
    781             mPcscfAddr = response.pcscf;
    782 
    783             result = updateLinkProperty(response).setupResult;
    784         }
    785 
    786         return result;
    787     }
    788 
    789     private boolean isDnsOk(String[] domainNameServers) {
    790         if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
    791                 && !mPhone.isDnsCheckDisabled()) {
    792             // Work around a race condition where QMI does not fill in DNS:
    793             // Deactivate PDP and let DataConnectionTracker retry.
    794             // Do not apply the race condition workaround for MMS APN
    795             // if Proxy is an IP-address.
    796             // Otherwise, the default APN will not be restored anymore.
    797             if (!mApnSetting.types[0].equals(PhoneConstants.APN_TYPE_MMS)
    798                 || !isIpAddress(mApnSetting.mmsProxy)) {
    799                 log(String.format(
    800                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
    801                         mApnSetting.types[0], PhoneConstants.APN_TYPE_MMS, mApnSetting.mmsProxy,
    802                         isIpAddress(mApnSetting.mmsProxy)));
    803                 return false;
    804             }
    805         }
    806         return true;
    807     }
    808 
    809     private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000";
    810     private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800";
    811     private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576";
    812     private static final String TCP_BUFFER_SIZES_1XRTT= "16384,32768,131072,4096,16384,102400";
    813     private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144";
    814     private static final String TCP_BUFFER_SIZES_EHRPD= "131072,262144,1048576,4096,16384,524288";
    815     private static final String TCP_BUFFER_SIZES_HSDPA= "61167,367002,1101005,8738,52429,262114";
    816     private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990";
    817     private static final String TCP_BUFFER_SIZES_LTE  =
    818             "524288,1048576,2097152,262144,524288,1048576";
    819     private static final String TCP_BUFFER_SIZES_HSPAP= "122334,734003,2202010,32040,192239,576717";
    820 
    821     private void updateTcpBufferSizes(int rilRat) {
    822         String sizes = null;
    823         String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT);
    824         // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex)
    825         // - patch it up:
    826         if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 ||
    827                 rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A ||
    828                 rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) {
    829             ratName = "evdo";
    830         }
    831 
    832         // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
    833         String[] configOverride = mPhone.getContext().getResources().getStringArray(
    834                 com.android.internal.R.array.config_mobile_tcp_buffers);
    835         for (int i = 0; i < configOverride.length; i++) {
    836             String[] split = configOverride[i].split(":");
    837             if (ratName.equals(split[0]) && split.length == 2) {
    838                 sizes = split[1];
    839                 break;
    840             }
    841         }
    842 
    843         if (sizes == null) {
    844             // no override - use telephony defaults
    845             // doing it this way allows device or carrier to just override the types they
    846             // care about and inherit the defaults for the others.
    847             switch (rilRat) {
    848                 case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS:
    849                     sizes = TCP_BUFFER_SIZES_GPRS;
    850                     break;
    851                 case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE:
    852                     sizes = TCP_BUFFER_SIZES_EDGE;
    853                     break;
    854                 case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS:
    855                     sizes = TCP_BUFFER_SIZES_UMTS;
    856                     break;
    857                 case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT:
    858                     sizes = TCP_BUFFER_SIZES_1XRTT;
    859                     break;
    860                 case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0:
    861                 case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A:
    862                 case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B:
    863                     sizes = TCP_BUFFER_SIZES_EVDO;
    864                     break;
    865                 case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD:
    866                     sizes = TCP_BUFFER_SIZES_EHRPD;
    867                     break;
    868                 case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA:
    869                     sizes = TCP_BUFFER_SIZES_HSDPA;
    870                     break;
    871                 case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA:
    872                 case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA:
    873                     sizes = TCP_BUFFER_SIZES_HSPA;
    874                     break;
    875                 case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
    876                     sizes = TCP_BUFFER_SIZES_LTE;
    877                     break;
    878                 case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
    879                     sizes = TCP_BUFFER_SIZES_HSPAP;
    880                     break;
    881                 default:
    882                     // Leave empty - this will let ConnectivityService use the system default.
    883                     break;
    884             }
    885         }
    886         mLinkProperties.setTcpBufferSizes(sizes);
    887     }
    888 
    889     private NetworkCapabilities makeNetworkCapabilities() {
    890         NetworkCapabilities result = new NetworkCapabilities();
    891         result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
    892 
    893         if (mApnSetting != null) {
    894             for (String type : mApnSetting.types) {
    895                 switch (type) {
    896                     case PhoneConstants.APN_TYPE_ALL: {
    897                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    898                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
    899                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
    900                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
    901                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
    902                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
    903                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
    904                         break;
    905                     }
    906                     case PhoneConstants.APN_TYPE_DEFAULT: {
    907                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    908                         break;
    909                     }
    910                     case PhoneConstants.APN_TYPE_MMS: {
    911                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
    912                         break;
    913                     }
    914                     case PhoneConstants.APN_TYPE_SUPL: {
    915                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
    916                         break;
    917                     }
    918                     case PhoneConstants.APN_TYPE_DUN: {
    919                         ApnSetting securedDunApn = mDct.fetchDunApn();
    920                         if (securedDunApn == null || securedDunApn.equals(mApnSetting)) {
    921                             result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
    922                         }
    923                         break;
    924                     }
    925                     case PhoneConstants.APN_TYPE_FOTA: {
    926                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
    927                         break;
    928                     }
    929                     case PhoneConstants.APN_TYPE_IMS: {
    930                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
    931                         break;
    932                     }
    933                     case PhoneConstants.APN_TYPE_CBS: {
    934                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
    935                         break;
    936                     }
    937                     case PhoneConstants.APN_TYPE_IA: {
    938                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
    939                         break;
    940                     }
    941                     default:
    942                 }
    943             }
    944             ConnectivityManager.maybeMarkCapabilitiesRestricted(result);
    945         }
    946         int up = 14;
    947         int down = 14;
    948         switch (mRilRat) {
    949             case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: up = 80; down = 80; break;
    950             case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: up = 59; down = 236; break;
    951             case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: up = 384; down = 384; break;
    952             case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A: // fall through
    953             case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B: up = 14; down = 14; break;
    954             case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: up = 153; down = 2457; break;
    955             case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: up = 1843; down = 3174; break;
    956             case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: up = 100; down = 100; break;
    957             case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: up = 2048; down = 14336; break;
    958             case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: up = 5898; down = 14336; break;
    959             case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: up = 5898; down = 14336; break;
    960             case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: up = 1843; down = 5017; break;
    961             case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: up = 51200; down = 102400; break;
    962             case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: up = 153; down = 2516; break;
    963             case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: up = 11264; down = 43008; break;
    964             default:
    965         }
    966         result.setLinkUpstreamBandwidthKbps(up);
    967         result.setLinkDownstreamBandwidthKbps(down);
    968         return result;
    969     }
    970 
    971     private boolean isIpAddress(String address) {
    972         if (address == null) return false;
    973 
    974         return Patterns.IP_ADDRESS.matcher(address).matches();
    975     }
    976 
    977     private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response,
    978             LinkProperties lp) {
    979         // Check if system property dns usable
    980         boolean okToUseSystemPropertyDns = false;
    981         String propertyPrefix = "net." + response.ifname + ".";
    982         String dnsServers[] = new String[2];
    983         dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
    984         dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
    985         okToUseSystemPropertyDns = isDnsOk(dnsServers);
    986 
    987         // set link properties based on data call response
    988         return response.setLinkProperties(lp, okToUseSystemPropertyDns);
    989     }
    990 
    991     /**
    992      * Initialize connection, this will fail if the
    993      * apnSettings are not compatible.
    994      *
    995      * @param cp the Connection paramemters
    996      * @return true if initialization was successful.
    997      */
    998     private boolean initConnection(ConnectionParams cp) {
    999         ApnContext apnContext = cp.mApnContext;
   1000         if (mApnSetting == null) {
   1001             // Only change apn setting if it isn't set, it will
   1002             // only NOT be set only if we're in DcInactiveState.
   1003             mApnSetting = apnContext.getApnSetting();
   1004         } else if (mApnSetting.canHandleType(apnContext.getApnType())) {
   1005             // All is good.
   1006         } else {
   1007             if (DBG) {
   1008                 log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp
   1009                         + " dc=" + DataConnection.this);
   1010             }
   1011             return false;
   1012         }
   1013         mTag += 1;
   1014         mConnectionParams = cp;
   1015         mConnectionParams.mTag = mTag;
   1016 
   1017         if (!mApnContexts.contains(apnContext)) {
   1018             mApnContexts.add(apnContext);
   1019         }
   1020         configureRetry(mApnSetting.canHandleType(PhoneConstants.APN_TYPE_DEFAULT));
   1021         mRetryManager.setRetryCount(0);
   1022         mRetryManager.setCurMaxRetryCount(mConnectionParams.mInitialMaxRetry);
   1023         mRetryManager.setRetryForever(false);
   1024 
   1025         if (DBG) {
   1026             log("initConnection: "
   1027                     + " RefCount=" + mApnContexts.size()
   1028                     + " mApnList=" + mApnContexts
   1029                     + " mConnectionParams=" + mConnectionParams);
   1030         }
   1031         return true;
   1032     }
   1033 
   1034     /**
   1035      * The parent state for all other states.
   1036      */
   1037     private class DcDefaultState extends State {
   1038         @Override
   1039         public void enter() {
   1040             if (DBG) log("DcDefaultState: enter");
   1041 
   1042             // Register for DRS or RAT change
   1043             mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),
   1044                     DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);
   1045 
   1046             mPhone.getServiceStateTracker().registerForRoamingOn(getHandler(),
   1047                     DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null);
   1048             mPhone.getServiceStateTracker().registerForRoamingOff(getHandler(),
   1049                     DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null);
   1050 
   1051             // Add ourselves to the list of data connections
   1052             mDcController.addDc(DataConnection.this);
   1053         }
   1054         @Override
   1055         public void exit() {
   1056             if (DBG) log("DcDefaultState: exit");
   1057 
   1058             // Unregister for DRS or RAT change.
   1059             mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler());
   1060 
   1061             mPhone.getServiceStateTracker().unregisterForRoamingOn(getHandler());
   1062             mPhone.getServiceStateTracker().unregisterForRoamingOff(getHandler());
   1063 
   1064             // Remove ourselves from the DC lists
   1065             mDcController.removeDc(DataConnection.this);
   1066 
   1067             if (mAc != null) {
   1068                 mAc.disconnected();
   1069                 mAc = null;
   1070             }
   1071             mDcRetryAlarmController.dispose();
   1072             mDcRetryAlarmController = null;
   1073             mApnContexts = null;
   1074             mReconnectIntent = null;
   1075             mDct = null;
   1076             mApnSetting = null;
   1077             mPhone = null;
   1078             mLinkProperties = null;
   1079             mLastFailCause = null;
   1080             mUserData = null;
   1081             mDcController = null;
   1082             mDcTesterFailBringUpAll = null;
   1083         }
   1084 
   1085         @Override
   1086         public boolean processMessage(Message msg) {
   1087             boolean retVal = HANDLED;
   1088 
   1089             if (VDBG) {
   1090                 log("DcDefault msg=" + getWhatToString(msg.what)
   1091                         + " RefCount=" + mApnContexts.size());
   1092             }
   1093             switch (msg.what) {
   1094                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
   1095                     if (mAc != null) {
   1096                         if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
   1097                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
   1098                                 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
   1099                     } else {
   1100                         mAc = new AsyncChannel();
   1101                         mAc.connected(null, getHandler(), msg.replyTo);
   1102                         if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
   1103                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
   1104                                 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
   1105                     }
   1106                     break;
   1107                 }
   1108                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
   1109                     if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
   1110                     quit();
   1111                     break;
   1112                 }
   1113                 case DcAsyncChannel.REQ_IS_INACTIVE: {
   1114                     boolean val = getIsInactive();
   1115                     if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
   1116                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_IS_INACTIVE, val ? 1 : 0);
   1117                     break;
   1118                 }
   1119                 case DcAsyncChannel.REQ_GET_CID: {
   1120                     int cid = getCid();
   1121                     if (VDBG) log("REQ_GET_CID  cid=" + cid);
   1122                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_CID, cid);
   1123                     break;
   1124                 }
   1125                 case DcAsyncChannel.REQ_GET_APNSETTING: {
   1126                     ApnSetting apnSetting = getApnSetting();
   1127                     if (VDBG) log("REQ_GET_APNSETTING  mApnSetting=" + apnSetting);
   1128                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_APNSETTING, apnSetting);
   1129                     break;
   1130                 }
   1131                 case DcAsyncChannel.REQ_GET_LINK_PROPERTIES: {
   1132                     LinkProperties lp = getCopyLinkProperties();
   1133                     if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
   1134                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_PROPERTIES, lp);
   1135                     break;
   1136                 }
   1137                 case DcAsyncChannel.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
   1138                     ProxyInfo proxy = (ProxyInfo) msg.obj;
   1139                     if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
   1140                     setLinkPropertiesHttpProxy(proxy);
   1141                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
   1142                     break;
   1143                 }
   1144                 case DcAsyncChannel.REQ_GET_NETWORK_CAPABILITIES: {
   1145                     NetworkCapabilities nc = getCopyNetworkCapabilities();
   1146                     if (VDBG) log("REQ_GET_NETWORK_CAPABILITIES networkCapabilities" + nc);
   1147                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_NETWORK_CAPABILITIES, nc);
   1148                     break;
   1149                 }
   1150                 case DcAsyncChannel.REQ_RESET:
   1151                     if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
   1152                     transitionTo(mInactiveState);
   1153                     break;
   1154                 case EVENT_CONNECT:
   1155                     if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
   1156                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1157                     notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false);
   1158                     break;
   1159 
   1160                 case EVENT_DISCONNECT:
   1161                     if (DBG) {
   1162                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount="
   1163                                 + mApnContexts.size());
   1164                     }
   1165                     deferMessage(msg);
   1166                     break;
   1167 
   1168                 case EVENT_DISCONNECT_ALL:
   1169                     if (DBG) {
   1170                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount="
   1171                                 + mApnContexts.size());
   1172                     }
   1173                     deferMessage(msg);
   1174                     break;
   1175 
   1176                 case EVENT_TEAR_DOWN_NOW:
   1177                     if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW");
   1178                     mPhone.mCi.deactivateDataCall(mCid, 0,  null);
   1179                     break;
   1180 
   1181                 case EVENT_LOST_CONNECTION:
   1182                     if (DBG) {
   1183                         String s = "DcDefaultState ignore EVENT_LOST_CONNECTION"
   1184                             + " tag=" + msg.arg1 + ":mTag=" + mTag;
   1185                         logAndAddLogRec(s);
   1186                     }
   1187                     break;
   1188 
   1189                 case EVENT_RETRY_CONNECTION:
   1190                     if (DBG) {
   1191                         String s = "DcDefaultState ignore EVENT_RETRY_CONNECTION"
   1192                                 + " tag=" + msg.arg1 + ":mTag=" + mTag;
   1193                         logAndAddLogRec(s);
   1194                     }
   1195                     break;
   1196 
   1197                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
   1198                     AsyncResult ar = (AsyncResult)msg.obj;
   1199                     Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
   1200                     mDataRegState = drsRatPair.first;
   1201                     if (mRilRat != drsRatPair.second) {
   1202                         updateTcpBufferSizes(drsRatPair.second);
   1203                     }
   1204                     mRilRat = drsRatPair.second;
   1205                     if (DBG) {
   1206                         log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
   1207                                 + " drs=" + mDataRegState
   1208                                 + " mRilRat=" + mRilRat);
   1209                     }
   1210                     ServiceState ss = mPhone.getServiceState();
   1211                     int networkType = ss.getDataNetworkType();
   1212                     mNetworkInfo.setSubtype(networkType,
   1213                             TelephonyManager.getNetworkTypeName(networkType));
   1214                     if (mNetworkAgent != null) {
   1215                         mNetworkAgent.sendNetworkCapabilities(makeNetworkCapabilities());
   1216                         mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   1217                         mNetworkAgent.sendLinkProperties(mLinkProperties);
   1218                     }
   1219                     break;
   1220 
   1221                 case EVENT_DATA_CONNECTION_ROAM_ON:
   1222                     mNetworkInfo.setRoaming(true);
   1223                     break;
   1224 
   1225                 case EVENT_DATA_CONNECTION_ROAM_OFF:
   1226                     mNetworkInfo.setRoaming(false);
   1227                     break;
   1228 
   1229                 default:
   1230                     if (DBG) {
   1231                         log("DcDefaultState: shouldn't happen but ignore msg.what="
   1232                                 + getWhatToString(msg.what));
   1233                     }
   1234                     break;
   1235             }
   1236 
   1237             return retVal;
   1238         }
   1239     }
   1240     private DcDefaultState mDefaultState = new DcDefaultState();
   1241 
   1242     /**
   1243      * The state machine is inactive and expects a EVENT_CONNECT.
   1244      */
   1245     private class DcInactiveState extends State {
   1246         // Inform all contexts we've failed connecting
   1247         public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) {
   1248             if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
   1249             mConnectionParams = cp;
   1250             mDisconnectParams = null;
   1251             mDcFailCause = cause;
   1252         }
   1253 
   1254         // Inform all contexts we've failed disconnected
   1255         public void setEnterNotificationParams(DisconnectParams dp) {
   1256             if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
   1257             mConnectionParams = null;
   1258             mDisconnectParams = dp;
   1259             mDcFailCause = DcFailCause.NONE;
   1260         }
   1261 
   1262         // Inform all contexts of the failure cause
   1263         public void setEnterNotificationParams(DcFailCause cause) {
   1264             mConnectionParams = null;
   1265             mDisconnectParams = null;
   1266             mDcFailCause = cause;
   1267         }
   1268 
   1269         @Override
   1270         public void enter() {
   1271             mTag += 1;
   1272             if (DBG) log("DcInactiveState: enter() mTag=" + mTag);
   1273 
   1274             if (mConnectionParams != null) {
   1275                 if (DBG) {
   1276                     log("DcInactiveState: enter notifyConnectCompleted +ALL failCause="
   1277                             + mDcFailCause);
   1278                 }
   1279                 notifyConnectCompleted(mConnectionParams, mDcFailCause, true);
   1280             }
   1281             if (mDisconnectParams != null) {
   1282                 if (DBG) {
   1283                     log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause="
   1284                             + mDcFailCause);
   1285                 }
   1286                 notifyDisconnectCompleted(mDisconnectParams, true);
   1287             }
   1288             if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) {
   1289                 if (DBG) {
   1290                     log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
   1291                             + mDcFailCause);
   1292                 }
   1293                 notifyAllDisconnectCompleted(mDcFailCause);
   1294             }
   1295 
   1296             // Remove ourselves from cid mapping, before clearSettings
   1297             mDcController.removeActiveDcByCid(DataConnection.this);
   1298 
   1299             clearSettings();
   1300         }
   1301 
   1302         @Override
   1303         public void exit() {
   1304         }
   1305 
   1306         @Override
   1307         public boolean processMessage(Message msg) {
   1308             boolean retVal;
   1309 
   1310             switch (msg.what) {
   1311                 case DcAsyncChannel.REQ_RESET:
   1312                     if (DBG) {
   1313                         log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
   1314                     }
   1315                     retVal = HANDLED;
   1316                     break;
   1317 
   1318                 case EVENT_CONNECT:
   1319                     if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
   1320                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1321                     if (initConnection(cp)) {
   1322                         onConnect(mConnectionParams);
   1323                         transitionTo(mActivatingState);
   1324                     } else {
   1325                         if (DBG) {
   1326                             log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
   1327                         }
   1328                         notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
   1329                                 false);
   1330                     }
   1331                     retVal = HANDLED;
   1332                     break;
   1333 
   1334                 case EVENT_DISCONNECT:
   1335                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
   1336                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
   1337                     retVal = HANDLED;
   1338                     break;
   1339 
   1340                 case EVENT_DISCONNECT_ALL:
   1341                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
   1342                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
   1343                     retVal = HANDLED;
   1344                     break;
   1345 
   1346                 default:
   1347                     if (VDBG) {
   1348                         log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what));
   1349                     }
   1350                     retVal = NOT_HANDLED;
   1351                     break;
   1352             }
   1353             return retVal;
   1354         }
   1355     }
   1356     private DcInactiveState mInactiveState = new DcInactiveState();
   1357 
   1358     /**
   1359      * The state machine is retrying and expects a EVENT_RETRY_CONNECTION.
   1360      */
   1361     private class DcRetryingState extends State {
   1362         @Override
   1363         public void enter() {
   1364             if ((mConnectionParams.mRilRat != mRilRat)
   1365                     || (mDataRegState != ServiceState.STATE_IN_SERVICE)){
   1366                 // RAT has changed or we're not in service so don't even begin retrying.
   1367                 if (DBG) {
   1368                     String s = "DcRetryingState: enter() not retrying rat changed"
   1369                         + ", mConnectionParams.mRilRat=" + mConnectionParams.mRilRat
   1370                         + " != mRilRat:" + mRilRat
   1371                         + " transitionTo(mInactiveState)";
   1372                     logAndAddLogRec(s);
   1373                 }
   1374                 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1375                 transitionTo(mInactiveState);
   1376             } else {
   1377                 if (DBG) {
   1378                     log("DcRetryingState: enter() mTag=" + mTag
   1379                         + ", call notifyAllOfDisconnectDcRetrying lostConnection");
   1380                 }
   1381 
   1382                 notifyAllOfDisconnectDcRetrying(Phone.REASON_LOST_DATA_CONNECTION);
   1383 
   1384                 // Remove ourselves from cid mapping
   1385                 mDcController.removeActiveDcByCid(DataConnection.this);
   1386                 mCid = -1;
   1387             }
   1388         }
   1389 
   1390         @Override
   1391         public boolean processMessage(Message msg) {
   1392             boolean retVal;
   1393 
   1394             switch (msg.what) {
   1395                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
   1396                     AsyncResult ar = (AsyncResult)msg.obj;
   1397                     Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
   1398                     int drs = drsRatPair.first;
   1399                     int rat = drsRatPair.second;
   1400                     if ((rat == mRilRat) && (drs == mDataRegState)) {
   1401                         if (DBG) {
   1402                             log("DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
   1403                                     + " strange no change in drs=" + drs
   1404                                     + " rat=" + rat + " ignoring");
   1405                         }
   1406                     } else {
   1407                         // have to retry connecting since no attach event will come
   1408                         if (mConnectionParams.mRetryWhenSSChange) {
   1409                             retVal = NOT_HANDLED;
   1410                             break;
   1411                         }
   1412                         // We've lost the connection and we're retrying but DRS or RAT changed
   1413                         // so we may never succeed, might as well give up.
   1414                         mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1415                         deferMessage(msg);
   1416                         transitionTo(mInactiveState);
   1417 
   1418                         if (DBG) {
   1419                             String s = "DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
   1420                                     + " giving up changed from " + mRilRat
   1421                                     + " to rat=" + rat
   1422                                     + " or drs changed from " + mDataRegState + " to drs=" + drs;
   1423                             logAndAddLogRec(s);
   1424                         }
   1425                         mDataRegState = drs;
   1426                         mRilRat = rat;
   1427                         // TODO - pass the other type here too?
   1428                         ServiceState ss = mPhone.getServiceState();
   1429                         int networkType = ss.getDataNetworkType();
   1430                         mNetworkInfo.setSubtype(networkType,
   1431                                 TelephonyManager.getNetworkTypeName(networkType));
   1432                     }
   1433                     retVal = HANDLED;
   1434                     break;
   1435 
   1436                 case EVENT_RETRY_CONNECTION: {
   1437                     if (msg.arg1 == mTag) {
   1438                         mRetryManager.increaseRetryCount();
   1439                         if (DBG) {
   1440                             log("DcRetryingState EVENT_RETRY_CONNECTION"
   1441                                     + " RetryCount=" +  mRetryManager.getRetryCount()
   1442                                     + " mConnectionParams=" + mConnectionParams);
   1443                         }
   1444                         onConnect(mConnectionParams);
   1445                         transitionTo(mActivatingState);
   1446                     } else {
   1447                         if (DBG) {
   1448                             log("DcRetryingState stale EVENT_RETRY_CONNECTION"
   1449                                     + " tag:" + msg.arg1 + " != mTag:" + mTag);
   1450                         }
   1451                     }
   1452                     retVal = HANDLED;
   1453                     break;
   1454                 }
   1455                 case DcAsyncChannel.REQ_RESET: {
   1456                     if (DBG) {
   1457                         log("DcRetryingState: msg.what=RSP_RESET, ignore we're already reset");
   1458                     }
   1459                     mInactiveState.setEnterNotificationParams(mConnectionParams,
   1460                             DcFailCause.RESET_BY_FRAMEWORK);
   1461                     transitionTo(mInactiveState);
   1462                     retVal = HANDLED;
   1463                     break;
   1464                 }
   1465                 case EVENT_CONNECT: {
   1466                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1467                     if (DBG) {
   1468                         log("DcRetryingState: msg.what=EVENT_CONNECT"
   1469                                 + " RefCount=" + mApnContexts.size() + " cp=" + cp
   1470                                 + " mConnectionParams=" + mConnectionParams);
   1471                     }
   1472                     if (initConnection(cp)) {
   1473                         onConnect(mConnectionParams);
   1474                         transitionTo(mActivatingState);
   1475                     } else {
   1476                         if (DBG) {
   1477                             log("DcRetryingState: msg.what=EVENT_CONNECT initConnection failed");
   1478                         }
   1479                         notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
   1480                                 false);
   1481                     }
   1482                     retVal = HANDLED;
   1483                     break;
   1484                 }
   1485                 case EVENT_DISCONNECT: {
   1486                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1487 
   1488                     if (mApnContexts.remove(dp.mApnContext) && mApnContexts.size() == 0) {
   1489                         if (DBG) {
   1490                             log("DcRetryingState msg.what=EVENT_DISCONNECT " + " RefCount="
   1491                                     + mApnContexts.size() + " dp=" + dp);
   1492                         }
   1493                         mInactiveState.setEnterNotificationParams(dp);
   1494                         transitionTo(mInactiveState);
   1495                     } else {
   1496                         if (DBG) log("DcRetryingState: msg.what=EVENT_DISCONNECT");
   1497                         notifyDisconnectCompleted(dp, false);
   1498                     }
   1499                     retVal = HANDLED;
   1500                     break;
   1501                 }
   1502                 case EVENT_DISCONNECT_ALL: {
   1503                     if (DBG) {
   1504                         log("DcRetryingState msg.what=EVENT_DISCONNECT/DISCONNECT_ALL "
   1505                                 + "RefCount=" + mApnContexts.size());
   1506                     }
   1507                     mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1508                     transitionTo(mInactiveState);
   1509                     retVal = HANDLED;
   1510                     break;
   1511                 }
   1512                 default: {
   1513                     if (VDBG) {
   1514                         log("DcRetryingState nothandled msg.what=" + getWhatToString(msg.what));
   1515                     }
   1516                     retVal = NOT_HANDLED;
   1517                     break;
   1518                 }
   1519             }
   1520             return retVal;
   1521         }
   1522     }
   1523     private DcRetryingState mRetryingState = new DcRetryingState();
   1524 
   1525     /**
   1526      * The state machine is activating a connection.
   1527      */
   1528     private class DcActivatingState extends State {
   1529         @Override
   1530         public boolean processMessage(Message msg) {
   1531             boolean retVal;
   1532             AsyncResult ar;
   1533             ConnectionParams cp;
   1534 
   1535             if (DBG) log("DcActivatingState: msg=" + msgToString(msg));
   1536             switch (msg.what) {
   1537                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
   1538                 case EVENT_CONNECT:
   1539                     // Activating can't process until we're done.
   1540                     deferMessage(msg);
   1541                     retVal = HANDLED;
   1542                     break;
   1543 
   1544                 case EVENT_SETUP_DATA_CONNECTION_DONE:
   1545                     ar = (AsyncResult) msg.obj;
   1546                     cp = (ConnectionParams) ar.userObj;
   1547 
   1548                     DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);
   1549                     if (result != DataCallResponse.SetupResult.ERR_Stale) {
   1550                         if (mConnectionParams != cp) {
   1551                             loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams
   1552                                     + " != cp:" + cp);
   1553                         }
   1554                     }
   1555                     if (DBG) {
   1556                         log("DcActivatingState onSetupConnectionCompleted result=" + result
   1557                                 + " dc=" + DataConnection.this);
   1558                     }
   1559                     switch (result) {
   1560                         case SUCCESS:
   1561                             // All is well
   1562                             mDcFailCause = DcFailCause.NONE;
   1563                             transitionTo(mActiveState);
   1564                             break;
   1565                         case ERR_BadCommand:
   1566                             // Vendor ril rejected the command and didn't connect.
   1567                             // Transition to inactive but send notifications after
   1568                             // we've entered the mInactive state.
   1569                             mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1570                             transitionTo(mInactiveState);
   1571                             break;
   1572                         case ERR_UnacceptableParameter:
   1573                             // The addresses given from the RIL are bad
   1574                             tearDownData(cp);
   1575                             transitionTo(mDisconnectingErrorCreatingConnection);
   1576                             break;
   1577                         case ERR_GetLastErrorFromRil:
   1578                             // Request failed and this is an old RIL
   1579                             mPhone.mCi.getLastDataCallFailCause(
   1580                                     obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
   1581                             break;
   1582                         case ERR_RilError:
   1583                             int delay = mDcRetryAlarmController.getSuggestedRetryTime(
   1584                                                                     DataConnection.this, ar);
   1585                             if (DBG) {
   1586                                 log("DcActivatingState: ERR_RilError "
   1587                                         + " delay=" + delay
   1588                                         + " isRetryNeeded=" + mRetryManager.isRetryNeeded()
   1589                                         + " result=" + result
   1590                                         + " result.isRestartRadioFail=" +
   1591                                         result.mFailCause.isRestartRadioFail()
   1592                                         + " result.isPermanentFail=" +
   1593                                         mDct.isPermanentFail(result.mFailCause));
   1594                             }
   1595                             if (result.mFailCause.isRestartRadioFail()) {
   1596                                 if (DBG) log("DcActivatingState: ERR_RilError restart radio");
   1597                                 mDct.sendRestartRadio();
   1598                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1599                                 transitionTo(mInactiveState);
   1600                             } else if (mDct.isPermanentFail(result.mFailCause)) {
   1601                                 if (DBG) log("DcActivatingState: ERR_RilError perm error");
   1602                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1603                                 transitionTo(mInactiveState);
   1604                             } else if (delay >= 0) {
   1605                                 if (DBG) log("DcActivatingState: ERR_RilError retry");
   1606                                 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION,
   1607                                                             mTag, delay);
   1608                                 transitionTo(mRetryingState);
   1609                             } else {
   1610                                 if (DBG) log("DcActivatingState: ERR_RilError no retry");
   1611                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1612                                 transitionTo(mInactiveState);
   1613                             }
   1614                             break;
   1615                         case ERR_Stale:
   1616                             loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE"
   1617                                     + " tag:" + cp.mTag + " != mTag:" + mTag);
   1618                             break;
   1619                         default:
   1620                             throw new RuntimeException("Unknown SetupResult, should not happen");
   1621                     }
   1622                     retVal = HANDLED;
   1623                     break;
   1624 
   1625                 case EVENT_GET_LAST_FAIL_DONE:
   1626                     ar = (AsyncResult) msg.obj;
   1627                     cp = (ConnectionParams) ar.userObj;
   1628                     if (cp.mTag == mTag) {
   1629                         if (mConnectionParams != cp) {
   1630                             loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams
   1631                                     + " != cp:" + cp);
   1632                         }
   1633 
   1634                         DcFailCause cause = DcFailCause.UNKNOWN;
   1635 
   1636                         if (ar.exception == null) {
   1637                             int rilFailCause = ((int[]) (ar.result))[0];
   1638                             cause = DcFailCause.fromInt(rilFailCause);
   1639                             if (cause == DcFailCause.NONE) {
   1640                                 if (DBG) {
   1641                                     log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
   1642                                             + " BAD: error was NONE, change to UNKNOWN");
   1643                                 }
   1644                                 cause = DcFailCause.UNKNOWN;
   1645                             }
   1646                         }
   1647                         mDcFailCause = cause;
   1648 
   1649                         int retryDelay = mRetryManager.getRetryTimer();
   1650                         if (DBG) {
   1651                             log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
   1652                                     + " cause=" + cause
   1653                                     + " retryDelay=" + retryDelay
   1654                                     + " isRetryNeeded=" + mRetryManager.isRetryNeeded()
   1655                                     + " dc=" + DataConnection.this);
   1656                         }
   1657                         if (cause.isRestartRadioFail()) {
   1658                             if (DBG) {
   1659                                 log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE"
   1660                                         + " restart radio");
   1661                             }
   1662                             mDct.sendRestartRadio();
   1663                             mInactiveState.setEnterNotificationParams(cp, cause);
   1664                             transitionTo(mInactiveState);
   1665                         } else if (mDct.isPermanentFail(cause)) {
   1666                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE perm er");
   1667                             mInactiveState.setEnterNotificationParams(cp, cause);
   1668                             transitionTo(mInactiveState);
   1669                         } else if ((retryDelay >= 0) && (mRetryManager.isRetryNeeded())) {
   1670                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE retry");
   1671                             mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
   1672                                                             retryDelay);
   1673                             transitionTo(mRetryingState);
   1674                         } else {
   1675                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE no retry");
   1676                             mInactiveState.setEnterNotificationParams(cp, cause);
   1677                             transitionTo(mInactiveState);
   1678                         }
   1679                     } else {
   1680                         loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE"
   1681                                 + " tag:" + cp.mTag + " != mTag:" + mTag);
   1682                     }
   1683 
   1684                     retVal = HANDLED;
   1685                     break;
   1686 
   1687                 default:
   1688                     if (VDBG) {
   1689                         log("DcActivatingState not handled msg.what=" +
   1690                                 getWhatToString(msg.what) + " RefCount=" + mApnContexts.size());
   1691                     }
   1692                     retVal = NOT_HANDLED;
   1693                     break;
   1694             }
   1695             return retVal;
   1696         }
   1697     }
   1698     private DcActivatingState mActivatingState = new DcActivatingState();
   1699 
   1700     /**
   1701      * The state machine is connected, expecting an EVENT_DISCONNECT.
   1702      */
   1703     private class DcActiveState extends State {
   1704         @Override public void enter() {
   1705             if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
   1706 
   1707             if (mRetryManager.getRetryCount() != 0) {
   1708                 log("DcActiveState: connected after retrying call notifyAllOfConnected");
   1709                 mRetryManager.setRetryCount(0);
   1710             }
   1711             // If we were retrying there maybe more than one, otherwise they'll only be one.
   1712             notifyAllOfConnected(Phone.REASON_CONNECTED);
   1713 
   1714             // If the EVENT_CONNECT set the current max retry restore it here
   1715             // if it didn't then this is effectively a NOP.
   1716             mRetryManager.restoreCurMaxRetryCount();
   1717             mDcController.addActiveDcByCid(DataConnection.this);
   1718 
   1719             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED,
   1720                     mNetworkInfo.getReason(), null);
   1721             mNetworkInfo.setExtraInfo(mApnSetting.apn);
   1722             updateTcpBufferSizes(mRilRat);
   1723             mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
   1724                     "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
   1725                     50);
   1726         }
   1727 
   1728         @Override
   1729         public void exit() {
   1730             if (DBG) log("DcActiveState: exit dc=" + this);
   1731             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
   1732                     mNetworkInfo.getReason(), mNetworkInfo.getExtraInfo());
   1733             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   1734             mNetworkAgent = null;
   1735         }
   1736 
   1737         @Override
   1738         public boolean processMessage(Message msg) {
   1739             boolean retVal;
   1740 
   1741             switch (msg.what) {
   1742                 case EVENT_CONNECT: {
   1743                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1744                     if (DBG) {
   1745                         log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this);
   1746                     }
   1747                     if (mApnContexts.contains(cp.mApnContext)) {
   1748                         log("DcActiveState ERROR already added apnContext=" + cp.mApnContext);
   1749                     } else {
   1750                         mApnContexts.add(cp.mApnContext);
   1751                         if (DBG) {
   1752                             log("DcActiveState msg.what=EVENT_CONNECT RefCount="
   1753                                     + mApnContexts.size());
   1754                         }
   1755                     }
   1756                     notifyConnectCompleted(cp, DcFailCause.NONE, false);
   1757                     retVal = HANDLED;
   1758                     break;
   1759                 }
   1760                 case EVENT_DISCONNECT: {
   1761                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1762                     if (DBG) {
   1763                         log("DcActiveState: EVENT_DISCONNECT dp=" + dp
   1764                                 + " dc=" + DataConnection.this);
   1765                     }
   1766                     if (mApnContexts.contains(dp.mApnContext)) {
   1767                         if (DBG) {
   1768                             log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
   1769                                     + mApnContexts.size());
   1770                         }
   1771 
   1772                         if (mApnContexts.size() == 1) {
   1773                             mApnContexts.clear();
   1774                             mDisconnectParams = dp;
   1775                             mConnectionParams = null;
   1776                             dp.mTag = mTag;
   1777                             tearDownData(dp);
   1778                             transitionTo(mDisconnectingState);
   1779                         } else {
   1780                             mApnContexts.remove(dp.mApnContext);
   1781                             notifyDisconnectCompleted(dp, false);
   1782                         }
   1783                     } else {
   1784                         log("DcActiveState ERROR no such apnContext=" + dp.mApnContext
   1785                                 + " in this dc=" + DataConnection.this);
   1786                         notifyDisconnectCompleted(dp, false);
   1787                     }
   1788                     retVal = HANDLED;
   1789                     break;
   1790                 }
   1791                 case EVENT_DISCONNECT_ALL: {
   1792                     if (DBG) {
   1793                         log("DcActiveState EVENT_DISCONNECT clearing apn contexts,"
   1794                                 + " dc=" + DataConnection.this);
   1795                     }
   1796                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1797                     mDisconnectParams = dp;
   1798                     mConnectionParams = null;
   1799                     dp.mTag = mTag;
   1800                     tearDownData(dp);
   1801                     transitionTo(mDisconnectingState);
   1802                     retVal = HANDLED;
   1803                     break;
   1804                 }
   1805                 case EVENT_LOST_CONNECTION: {
   1806                     if (DBG) {
   1807                         log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this);
   1808                     }
   1809                     if (mRetryManager.isRetryNeeded()) {
   1810                         // We're going to retry
   1811                         int delayMillis = mRetryManager.getRetryTimer();
   1812                         if (DBG) {
   1813                             log("DcActiveState EVENT_LOST_CONNECTION startRetryAlarm"
   1814                                     + " mTag=" + mTag + " delay=" + delayMillis + "ms");
   1815                         }
   1816                         mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
   1817                                 delayMillis);
   1818                         transitionTo(mRetryingState);
   1819                     } else {
   1820                         mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1821                         transitionTo(mInactiveState);
   1822                     }
   1823                     retVal = HANDLED;
   1824                     break;
   1825                 }
   1826                 case EVENT_DATA_CONNECTION_ROAM_ON: {
   1827                     mNetworkInfo.setRoaming(true);
   1828                     mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   1829                     retVal = HANDLED;
   1830                     break;
   1831                 }
   1832                 case EVENT_DATA_CONNECTION_ROAM_OFF: {
   1833                     mNetworkInfo.setRoaming(false);
   1834                     mNetworkAgent.sendNetworkInfo(mNetworkInfo);
   1835                     retVal = HANDLED;
   1836                     break;
   1837                 }
   1838                 default:
   1839                     if (VDBG) {
   1840                         log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
   1841                     }
   1842                     retVal = NOT_HANDLED;
   1843                     break;
   1844             }
   1845             return retVal;
   1846         }
   1847     }
   1848     private DcActiveState mActiveState = new DcActiveState();
   1849 
   1850     /**
   1851      * The state machine is disconnecting.
   1852      */
   1853     private class DcDisconnectingState extends State {
   1854         @Override
   1855         public boolean processMessage(Message msg) {
   1856             boolean retVal;
   1857 
   1858             switch (msg.what) {
   1859                 case EVENT_CONNECT:
   1860                     if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
   1861                             + mApnContexts.size());
   1862                     deferMessage(msg);
   1863                     retVal = HANDLED;
   1864                     break;
   1865 
   1866                 case EVENT_DEACTIVATE_DONE:
   1867                     if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount="
   1868                             + mApnContexts.size());
   1869                     AsyncResult ar = (AsyncResult) msg.obj;
   1870                     DisconnectParams dp = (DisconnectParams) ar.userObj;
   1871                     if (dp.mTag == mTag) {
   1872                         // Transition to inactive but send notifications after
   1873                         // we've entered the mInactive state.
   1874                         mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
   1875                         transitionTo(mInactiveState);
   1876                     } else {
   1877                         if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE"
   1878                                 + " dp.tag=" + dp.mTag + " mTag=" + mTag);
   1879                     }
   1880                     retVal = HANDLED;
   1881                     break;
   1882 
   1883                 default:
   1884                     if (VDBG) {
   1885                         log("DcDisconnectingState not handled msg.what="
   1886                                 + getWhatToString(msg.what));
   1887                     }
   1888                     retVal = NOT_HANDLED;
   1889                     break;
   1890             }
   1891             return retVal;
   1892         }
   1893     }
   1894     private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
   1895 
   1896     /**
   1897      * The state machine is disconnecting after an creating a connection.
   1898      */
   1899     private class DcDisconnectionErrorCreatingConnection extends State {
   1900         @Override
   1901         public boolean processMessage(Message msg) {
   1902             boolean retVal;
   1903 
   1904             switch (msg.what) {
   1905                 case EVENT_DEACTIVATE_DONE:
   1906                     AsyncResult ar = (AsyncResult) msg.obj;
   1907                     ConnectionParams cp = (ConnectionParams) ar.userObj;
   1908                     if (cp.mTag == mTag) {
   1909                         if (DBG) {
   1910                             log("DcDisconnectionErrorCreatingConnection" +
   1911                                 " msg.what=EVENT_DEACTIVATE_DONE");
   1912                         }
   1913 
   1914                         // Transition to inactive but send notifications after
   1915                         // we've entered the mInactive state.
   1916                         mInactiveState.setEnterNotificationParams(cp,
   1917                                 DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
   1918                         transitionTo(mInactiveState);
   1919                     } else {
   1920                         if (DBG) {
   1921                             log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE"
   1922                                     + " dp.tag=" + cp.mTag + ", mTag=" + mTag);
   1923                         }
   1924                     }
   1925                     retVal = HANDLED;
   1926                     break;
   1927 
   1928                 default:
   1929                     if (VDBG) {
   1930                         log("DcDisconnectionErrorCreatingConnection not handled msg.what="
   1931                                 + getWhatToString(msg.what));
   1932                     }
   1933                     retVal = NOT_HANDLED;
   1934                     break;
   1935             }
   1936             return retVal;
   1937         }
   1938     }
   1939     private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
   1940                 new DcDisconnectionErrorCreatingConnection();
   1941 
   1942 
   1943     private class DcNetworkAgent extends NetworkAgent {
   1944         public DcNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
   1945                 NetworkCapabilities nc, LinkProperties lp, int score) {
   1946             super(l, c, TAG, ni, nc, lp, score);
   1947         }
   1948 
   1949         protected void unwanted() {
   1950             if (mNetworkAgent != this) {
   1951                 log("unwanted found mNetworkAgent=" + mNetworkAgent +
   1952                         ", which isn't me.  Aborting unwanted");
   1953                 return;
   1954             }
   1955             // this can only happen if our exit has been called - we're already disconnected
   1956             if (mApnContexts == null) return;
   1957             for (ApnContext apnContext : mApnContexts) {
   1958                 Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);
   1959                 DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg);
   1960                 DataConnection.this.sendMessage(DataConnection.this.
   1961                         obtainMessage(EVENT_DISCONNECT, dp));
   1962             }
   1963         }
   1964     }
   1965 
   1966     // ******* "public" interface
   1967 
   1968     /**
   1969      * Used for testing purposes.
   1970      */
   1971     /* package */ void tearDownNow() {
   1972         if (DBG) log("tearDownNow()");
   1973         sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW));
   1974     }
   1975 
   1976     /**
   1977      * @return the string for msg.what as our info.
   1978      */
   1979     @Override
   1980     protected String getWhatToString(int what) {
   1981         return cmdToString(what);
   1982     }
   1983 
   1984     private static String msgToString(Message msg) {
   1985         String retVal;
   1986         if (msg == null) {
   1987             retVal = "null";
   1988         } else {
   1989             StringBuilder   b = new StringBuilder();
   1990 
   1991             b.append("{what=");
   1992             b.append(cmdToString(msg.what));
   1993 
   1994             b.append(" when=");
   1995             TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b);
   1996 
   1997             if (msg.arg1 != 0) {
   1998                 b.append(" arg1=");
   1999                 b.append(msg.arg1);
   2000             }
   2001 
   2002             if (msg.arg2 != 0) {
   2003                 b.append(" arg2=");
   2004                 b.append(msg.arg2);
   2005             }
   2006 
   2007             if (msg.obj != null) {
   2008                 b.append(" obj=");
   2009                 b.append(msg.obj);
   2010             }
   2011 
   2012             b.append(" target=");
   2013             b.append(msg.getTarget());
   2014 
   2015             b.append(" replyTo=");
   2016             b.append(msg.replyTo);
   2017 
   2018             b.append("}");
   2019 
   2020             retVal = b.toString();
   2021         }
   2022         return retVal;
   2023     }
   2024 
   2025     static void slog(String s) {
   2026         Rlog.d("DC", s);
   2027     }
   2028 
   2029     /**
   2030      * Log with debug
   2031      *
   2032      * @param s is string log
   2033      */
   2034     @Override
   2035     protected void log(String s) {
   2036         Rlog.d(getName(), s);
   2037     }
   2038 
   2039     /**
   2040      * Log with debug attribute
   2041      *
   2042      * @param s is string log
   2043      */
   2044     @Override
   2045     protected void logd(String s) {
   2046         Rlog.d(getName(), s);
   2047     }
   2048 
   2049     /**
   2050      * Log with verbose attribute
   2051      *
   2052      * @param s is string log
   2053      */
   2054     @Override
   2055     protected void logv(String s) {
   2056         Rlog.v(getName(), s);
   2057     }
   2058 
   2059     /**
   2060      * Log with info attribute
   2061      *
   2062      * @param s is string log
   2063      */
   2064     @Override
   2065     protected void logi(String s) {
   2066         Rlog.i(getName(), s);
   2067     }
   2068 
   2069     /**
   2070      * Log with warning attribute
   2071      *
   2072      * @param s is string log
   2073      */
   2074     @Override
   2075     protected void logw(String s) {
   2076         Rlog.w(getName(), s);
   2077     }
   2078 
   2079     /**
   2080      * Log with error attribute
   2081      *
   2082      * @param s is string log
   2083      */
   2084     @Override
   2085     protected void loge(String s) {
   2086         Rlog.e(getName(), s);
   2087     }
   2088 
   2089     /**
   2090      * Log with error attribute
   2091      *
   2092      * @param s is string log
   2093      * @param e is a Throwable which logs additional information.
   2094      */
   2095     @Override
   2096     protected void loge(String s, Throwable e) {
   2097         Rlog.e(getName(), s, e);
   2098     }
   2099 
   2100     /** Doesn't print mApnList of ApnContext's which would be recursive */
   2101     public String toStringSimple() {
   2102         return getName() + ": State=" + getCurrentState().getName()
   2103                 + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size()
   2104                 + " mCid=" + mCid + " mCreateTime=" + mCreateTime
   2105                 + " mLastastFailTime=" + mLastFailTime
   2106                 + " mLastFailCause=" + mLastFailCause
   2107                 + " mTag=" + mTag
   2108                 + " mRetryManager=" + mRetryManager
   2109                 + " mLinkProperties=" + mLinkProperties
   2110                 + " linkCapabilities=" + makeNetworkCapabilities();
   2111     }
   2112 
   2113     @Override
   2114     public String toString() {
   2115         return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}";
   2116     }
   2117 
   2118     /**
   2119      * Dump the current state.
   2120      *
   2121      * @param fd
   2122      * @param pw
   2123      * @param args
   2124      */
   2125     @Override
   2126     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2127         pw.print("DataConnection ");
   2128         super.dump(fd, pw, args);
   2129         pw.println(" mApnContexts.size=" + mApnContexts.size());
   2130         pw.println(" mApnContexts=" + mApnContexts);
   2131         pw.flush();
   2132         pw.println(" mDataConnectionTracker=" + mDct);
   2133         pw.println(" mApnSetting=" + mApnSetting);
   2134         pw.println(" mTag=" + mTag);
   2135         pw.println(" mCid=" + mCid);
   2136         pw.println(" mRetryManager=" + mRetryManager);
   2137         pw.println(" mConnectionParams=" + mConnectionParams);
   2138         pw.println(" mDisconnectParams=" + mDisconnectParams);
   2139         pw.println(" mDcFailCause=" + mDcFailCause);
   2140         pw.flush();
   2141         pw.println(" mPhone=" + mPhone);
   2142         pw.flush();
   2143         pw.println(" mLinkProperties=" + mLinkProperties);
   2144         pw.flush();
   2145         pw.println(" mDataRegState=" + mDataRegState);
   2146         pw.println(" mRilRat=" + mRilRat);
   2147         pw.println(" mNetworkCapabilities=" + makeNetworkCapabilities());
   2148         pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
   2149         pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
   2150         pw.println(" mLastFailCause=" + mLastFailCause);
   2151         pw.flush();
   2152         pw.println(" mUserData=" + mUserData);
   2153         pw.println(" mInstanceNumber=" + mInstanceNumber);
   2154         pw.println(" mAc=" + mAc);
   2155         pw.println(" mDcRetryAlarmController=" + mDcRetryAlarmController);
   2156         pw.flush();
   2157     }
   2158 }
   2159