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.net.LinkCapabilities;
     34 import android.net.LinkProperties;
     35 import android.net.ProxyProperties;
     36 import android.os.AsyncResult;
     37 import android.os.Build;
     38 import android.os.Message;
     39 import android.os.SystemClock;
     40 import android.os.SystemProperties;
     41 import android.telephony.Rlog;
     42 import android.telephony.ServiceState;
     43 import android.telephony.TelephonyManager;
     44 import android.text.TextUtils;
     45 import android.util.Pair;
     46 import android.util.Patterns;
     47 import android.util.TimeUtils;
     48 
     49 import java.io.FileDescriptor;
     50 import java.io.PrintWriter;
     51 import java.util.ArrayList;
     52 import java.util.List;
     53 import java.util.concurrent.atomic.AtomicInteger;
     54 
     55 /**
     56  * {@hide}
     57  *
     58  * DataConnection StateMachine.
     59  *
     60  * This a class for representing a single data connection, with instances of this
     61  * class representing a connection via the cellular network. There may be multiple
     62  * data connections and all of them are managed by the <code>DataConnectionTracker</code>.
     63  *
     64  * A recent change is to move retry handling into this class, with that change the
     65  * old retry manager is now used internally rather than exposed to the DCT. Also,
     66  * bringUp now has an initialRetry which is used limit the number of retries
     67  * during the initial bring up of the connection. After the connection becomes active
     68  * the current max retry is restored to the configured value.
     69  *
     70  * NOTE: All DataConnection objects must be running on the same looper, which is the default
     71  * as the coordinator has members which are used without synchronization.
     72  */
     73 public final class DataConnection extends StateMachine {
     74     private static final boolean DBG = true;
     75     private static final boolean VDBG = true;
     76 
     77     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
     78     private static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
     79         + "5000,10000,20000,40000,80000:5000,160000:5000,"
     80         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
     81 
     82     /** Retry configuration for secondary networks: 4 tries in 20 sec */
     83     private static final String SECONDARY_DATA_RETRY_CONFIG =
     84             "max_retries=3, 5000, 5000, 5000";
     85 
     86     // The data connection controller
     87     private DcController mDcController;
     88 
     89     // The Tester for failing all bringup's
     90     private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
     91 
     92     private static AtomicInteger mInstanceNumber = new AtomicInteger(0);
     93     private AsyncChannel mAc;
     94 
     95     // Utilities for the DataConnection
     96     private DcRetryAlarmController mDcRetryAlarmController;
     97 
     98     // The DCT that's talking to us, we only support one!
     99     private DcTrackerBase mDct = null;
    100 
    101     /**
    102      * Used internally for saving connecting parameters.
    103      */
    104     static class ConnectionParams {
    105         int mTag;
    106         ApnContext mApnContext;
    107         int mInitialMaxRetry;
    108         int mProfileId;
    109         int mRilRat;
    110         Message mOnCompletedMsg;
    111 
    112         ConnectionParams(ApnContext apnContext, int initialMaxRetry, int profileId,
    113                 int rilRadioTechnology, Message onCompletedMsg) {
    114             mApnContext = apnContext;
    115             mInitialMaxRetry = initialMaxRetry;
    116             mProfileId = profileId;
    117             mRilRat = rilRadioTechnology;
    118             mOnCompletedMsg = onCompletedMsg;
    119         }
    120 
    121         @Override
    122         public String toString() {
    123             return "{mTag=" + mTag + " mApnContext=" + mApnContext
    124                     + " mInitialMaxRetry=" + mInitialMaxRetry + " mProfileId=" + mProfileId
    125                     + " mRat=" + mRilRat
    126                     + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
    127         }
    128     }
    129 
    130     /**
    131      * Used internally for saving disconnecting parameters.
    132      */
    133     static class DisconnectParams {
    134         int mTag;
    135         ApnContext mApnContext;
    136         String mReason;
    137         Message mOnCompletedMsg;
    138 
    139         DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
    140             mApnContext = apnContext;
    141             mReason = reason;
    142             mOnCompletedMsg = onCompletedMsg;
    143         }
    144 
    145         @Override
    146         public String toString() {
    147             return "{mTag=" + mTag + " mApnContext=" + mApnContext
    148                     + " mReason=" + mReason
    149                     + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
    150         }
    151     }
    152 
    153     private ApnSetting mApnSetting;
    154     private ConnectionParams mConnectionParams;
    155     private DisconnectParams mDisconnectParams;
    156     private DcFailCause mDcFailCause;
    157 
    158     private PhoneBase mPhone;
    159     private LinkProperties mLinkProperties = new LinkProperties();
    160     private LinkCapabilities mLinkCapabilities = new LinkCapabilities();
    161     private long mCreateTime;
    162     private long mLastFailTime;
    163     private DcFailCause mLastFailCause;
    164     private static final String NULL_IP = "0.0.0.0";
    165     private Object mUserData;
    166     private int mRilRat = Integer.MAX_VALUE;
    167     private int mDataRegState = Integer.MAX_VALUE;
    168 
    169     //***** Package visible variables
    170     int mTag;
    171     int mCid;
    172     List<ApnContext> mApnContexts = null;
    173     PendingIntent mReconnectIntent = null;
    174     RetryManager mRetryManager = new RetryManager();
    175 
    176 
    177     // ***** Event codes for driving the state machine, package visible for Dcc
    178     static final int BASE = Protocol.BASE_DATA_CONNECTION;
    179     static final int EVENT_CONNECT = BASE + 0;
    180     static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
    181     static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
    182     static final int EVENT_DEACTIVATE_DONE = BASE + 3;
    183     static final int EVENT_DISCONNECT = BASE + 4;
    184     static final int EVENT_RIL_CONNECTED = BASE + 5;
    185     static final int EVENT_DISCONNECT_ALL = BASE + 6;
    186     static final int EVENT_DATA_STATE_CHANGED = BASE + 7;
    187     static final int EVENT_TEAR_DOWN_NOW = BASE + 8;
    188     static final int EVENT_LOST_CONNECTION = BASE + 9;
    189     static final int EVENT_RETRY_CONNECTION = BASE + 10;
    190     static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11;
    191 
    192     private static final int CMD_TO_STRING_COUNT = EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE + 1;
    193     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    194     static {
    195         sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
    196         sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
    197                 "EVENT_SETUP_DATA_CONNECTION_DONE";
    198         sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
    199         sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
    200         sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
    201         sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
    202         sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
    203         sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED";
    204         sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW";
    205         sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION";
    206         sCmdToString[EVENT_RETRY_CONNECTION - BASE] = "EVENT_RETRY_CONNECTION";
    207         sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] =
    208                 "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED";
    209     }
    210     // Convert cmd to string or null if unknown
    211     static String cmdToString(int cmd) {
    212         String value;
    213         cmd -= BASE;
    214         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
    215             value = sCmdToString[cmd];
    216         } else {
    217             value = DcAsyncChannel.cmdToString(cmd + BASE);
    218         }
    219         if (value == null) {
    220             value = "0x" + Integer.toHexString(cmd + BASE);
    221         }
    222         return value;
    223     }
    224 
    225     /**
    226      * Create the connection object
    227      *
    228      * @param phone the Phone
    229      * @param id the connection id
    230      * @return DataConnection that was created.
    231      */
    232     static DataConnection makeDataConnection(PhoneBase phone, int id,
    233             DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
    234             DcController dcc) {
    235         DataConnection dc = new DataConnection(phone,
    236                 "DC-" + mInstanceNumber.incrementAndGet(), id, dct, failBringUpAll, dcc);
    237         dc.start();
    238         if (DBG) dc.log("Made " + dc.getName());
    239         return dc;
    240     }
    241 
    242     void dispose() {
    243         log("dispose: call quiteNow()");
    244         quitNow();
    245     }
    246 
    247     /* Getter functions */
    248 
    249     LinkCapabilities getCopyLinkCapabilities() {
    250         return new LinkCapabilities(mLinkCapabilities);
    251     }
    252 
    253     LinkProperties getCopyLinkProperties() {
    254         return new LinkProperties(mLinkProperties);
    255     }
    256 
    257     boolean getIsInactive() {
    258         return getCurrentState() == mInactiveState;
    259     }
    260 
    261     int getCid() {
    262         return mCid;
    263     }
    264 
    265     ApnSetting getApnSetting() {
    266         return mApnSetting;
    267     }
    268 
    269     void setLinkPropertiesHttpProxy(ProxyProperties proxy) {
    270         mLinkProperties.setHttpProxy(proxy);
    271     }
    272 
    273     static class UpdateLinkPropertyResult {
    274         public DataCallResponse.SetupResult setupResult = DataCallResponse.SetupResult.SUCCESS;
    275         public LinkProperties oldLp;
    276         public LinkProperties newLp;
    277         public UpdateLinkPropertyResult(LinkProperties curLp) {
    278             oldLp = curLp;
    279             newLp = curLp;
    280         }
    281     }
    282 
    283     UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) {
    284         UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
    285 
    286         if (newState == null) return result;
    287 
    288         DataCallResponse.SetupResult setupResult;
    289         result.newLp = new LinkProperties();
    290 
    291         // set link properties based on data call response
    292         result.setupResult = setLinkProperties(newState, result.newLp);
    293         if (result.setupResult != DataCallResponse.SetupResult.SUCCESS) {
    294             if (DBG) log("updateLinkProperty failed : " + result.setupResult);
    295             return result;
    296         }
    297         // copy HTTP proxy as it is not part DataCallResponse.
    298         result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
    299 
    300         if (DBG && (! result.oldLp.equals(result.newLp))) {
    301             log("updateLinkProperty old LP=" + result.oldLp);
    302             log("updateLinkProperty new LP=" + result.newLp);
    303         }
    304         mLinkProperties = result.newLp;
    305 
    306         return result;
    307     }
    308 
    309     //***** Constructor (NOTE: uses dcc.getHandler() as its Handler)
    310     private DataConnection(PhoneBase phone, String name, int id,
    311                 DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
    312                 DcController dcc) {
    313         super(name, dcc.getHandler());
    314         setLogRecSize(300);
    315         setLogOnlyTransitions(true);
    316         if (DBG) log("DataConnection constructor E");
    317 
    318         mPhone = phone;
    319         mDct = dct;
    320         mDcTesterFailBringUpAll = failBringUpAll;
    321         mDcController = dcc;
    322         mId = id;
    323         mCid = -1;
    324         mDcRetryAlarmController = new DcRetryAlarmController(mPhone, this);
    325         mRilRat = mPhone.getServiceState().getRilDataRadioTechnology();
    326         mDataRegState = mPhone.getServiceState().getDataRegState();
    327 
    328         addState(mDefaultState);
    329             addState(mInactiveState, mDefaultState);
    330             addState(mActivatingState, mDefaultState);
    331             addState(mRetryingState, mDefaultState);
    332             addState(mActiveState, mDefaultState);
    333             addState(mDisconnectingState, mDefaultState);
    334             addState(mDisconnectingErrorCreatingConnection, mDefaultState);
    335         setInitialState(mInactiveState);
    336 
    337         mApnContexts = new ArrayList<ApnContext>();
    338         if (DBG) log("DataConnection constructor X");
    339     }
    340 
    341     private String getRetryConfig(boolean forDefault) {
    342         int nt = mPhone.getServiceState().getNetworkType();
    343 
    344         if (Build.IS_DEBUGGABLE) {
    345             String config = SystemProperties.get("test.data_retry_config");
    346             if (! TextUtils.isEmpty(config)) {
    347                 return config;
    348             }
    349         }
    350 
    351         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
    352             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
    353             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
    354             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
    355             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
    356             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
    357             // CDMA variant
    358             return SystemProperties.get("ro.cdma.data_retry_config");
    359         } else {
    360             // Use GSM variant for all others.
    361             if (forDefault) {
    362                 return SystemProperties.get("ro.gsm.data_retry_config");
    363             } else {
    364                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
    365             }
    366         }
    367     }
    368 
    369     private void configureRetry(boolean forDefault) {
    370         String retryConfig = getRetryConfig(forDefault);
    371 
    372         if (!mRetryManager.configure(retryConfig)) {
    373             if (forDefault) {
    374                 if (!mRetryManager.configure(DEFAULT_DATA_RETRY_CONFIG)) {
    375                     // Should never happen, log an error and default to a simple linear sequence.
    376                     loge("configureRetry: Could not configure using " +
    377                             "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
    378                     mRetryManager.configure(5, 2000, 1000);
    379                 }
    380             } else {
    381                 if (!mRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) {
    382                     // Should never happen, log an error and default to a simple sequence.
    383                     loge("configureRetry: Could note configure using " +
    384                             "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
    385                     mRetryManager.configure(5, 2000, 1000);
    386                 }
    387             }
    388         }
    389         if (DBG) {
    390             log("configureRetry: forDefault=" + forDefault + " mRetryManager=" + mRetryManager);
    391         }
    392     }
    393 
    394     /**
    395      * Begin setting up a data connection, calls setupDataCall
    396      * and the ConnectionParams will be returned with the
    397      * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
    398      *
    399      * @param cp is the connection parameters
    400      */
    401     private void onConnect(ConnectionParams cp) {
    402         if (DBG) log("onConnect: carrier='" + mApnSetting.carrier
    403                 + "' APN='" + mApnSetting.apn
    404                 + "' proxy='" + mApnSetting.proxy + "' port='" + mApnSetting.port + "'");
    405 
    406         // Check if we should fake an error.
    407         if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter  > 0) {
    408             DataCallResponse response = new DataCallResponse();
    409             response.version = mPhone.mCi.getRilVersion();
    410             response.status = mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause.getErrorCode();
    411             response.cid = 0;
    412             response.active = 0;
    413             response.type = "";
    414             response.ifname = "";
    415             response.addresses = new String[0];
    416             response.dnses = new String[0];
    417             response.gateways = new String[0];
    418             response.suggestedRetryTime =
    419                     mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime;
    420 
    421             Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
    422             AsyncResult.forMessage(msg, response, null);
    423             sendMessage(msg);
    424             if (DBG) {
    425                 log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp()
    426                         + " send error response=" + response);
    427             }
    428             mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1;
    429             return;
    430         }
    431 
    432         mCreateTime = -1;
    433         mLastFailTime = -1;
    434         mLastFailCause = DcFailCause.NONE;
    435 
    436         // msg.obj will be returned in AsyncResult.userObj;
    437         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
    438         msg.obj = cp;
    439 
    440         int authType = mApnSetting.authType;
    441         if (authType == -1) {
    442             authType = TextUtils.isEmpty(mApnSetting.user) ? RILConstants.SETUP_DATA_AUTH_NONE
    443                     : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
    444         }
    445 
    446         String protocol;
    447         if (mPhone.getServiceState().getRoaming()) {
    448             protocol = mApnSetting.roamingProtocol;
    449         } else {
    450             protocol = mApnSetting.protocol;
    451         }
    452 
    453         mPhone.mCi.setupDataCall(
    454                 Integer.toString(cp.mRilRat + 2),
    455                 Integer.toString(cp.mProfileId),
    456                 mApnSetting.apn, mApnSetting.user, mApnSetting.password,
    457                 Integer.toString(authType),
    458                 protocol, msg);
    459     }
    460 
    461     /**
    462      * TearDown the data connection when the deactivation is complete a Message with
    463      * msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj
    464      * containing the parameter o.
    465      *
    466      * @param o is the object returned in the AsyncResult.obj.
    467      */
    468     private void tearDownData(Object o) {
    469         int discReason = RILConstants.DEACTIVATE_REASON_NONE;
    470         if ((o != null) && (o instanceof DisconnectParams)) {
    471             DisconnectParams dp = (DisconnectParams)o;
    472 
    473             if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) {
    474                 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
    475             } else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {
    476                 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
    477             }
    478         }
    479         if (mPhone.mCi.getRadioState().isOn()) {
    480             if (DBG) log("tearDownData radio is on, call deactivateDataCall");
    481             mPhone.mCi.deactivateDataCall(mCid, discReason,
    482                     obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));
    483         } else {
    484             if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
    485             AsyncResult ar = new AsyncResult(o, null, null);
    486             sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar));
    487         }
    488     }
    489 
    490     private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) {
    491         for (ApnContext apnContext : mApnContexts) {
    492             if (apnContext == alreadySent) continue;
    493             if (reason != null) apnContext.setReason(reason);
    494             Message msg = mDct.obtainMessage(event, apnContext);
    495             AsyncResult.forMessage(msg);
    496             msg.sendToTarget();
    497         }
    498     }
    499 
    500     private void notifyAllOfConnected(String reason) {
    501         notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason);
    502     }
    503 
    504     private void notifyAllOfDisconnectDcRetrying(String reason) {
    505         notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DC_RETRYING, reason);
    506     }
    507     private void notifyAllDisconnectCompleted(DcFailCause cause) {
    508         notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, cause.toString());
    509     }
    510 
    511 
    512     /**
    513      * Send the connectionCompletedMsg.
    514      *
    515      * @param cp is the ConnectionParams
    516      * @param cause and if no error the cause is DcFailCause.NONE
    517      * @param sendAll is true if all contexts are to be notified
    518      */
    519     private void notifyConnectCompleted(ConnectionParams cp, DcFailCause cause, boolean sendAll) {
    520         ApnContext alreadySent = null;
    521 
    522         if (cp != null && cp.mOnCompletedMsg != null) {
    523             // Get the completed message but only use it once
    524             Message connectionCompletedMsg = cp.mOnCompletedMsg;
    525             cp.mOnCompletedMsg = null;
    526             if (connectionCompletedMsg.obj instanceof ApnContext) {
    527                 alreadySent = (ApnContext)connectionCompletedMsg.obj;
    528             }
    529 
    530             long timeStamp = System.currentTimeMillis();
    531             connectionCompletedMsg.arg1 = mCid;
    532 
    533             if (cause == DcFailCause.NONE) {
    534                 mCreateTime = timeStamp;
    535                 AsyncResult.forMessage(connectionCompletedMsg);
    536             } else {
    537                 mLastFailCause = cause;
    538                 mLastFailTime = timeStamp;
    539 
    540                 // Return message with a Throwable exception to signify an error.
    541                 if (cause == null) cause = DcFailCause.UNKNOWN;
    542                 AsyncResult.forMessage(connectionCompletedMsg, cause,
    543                         new Throwable(cause.toString()));
    544             }
    545             if (DBG) {
    546                 log("notifyConnectCompleted at " + timeStamp + " cause=" + cause
    547                         + " connectionCompletedMsg=" + msgToString(connectionCompletedMsg));
    548             }
    549 
    550             connectionCompletedMsg.sendToTarget();
    551         }
    552         if (sendAll) {
    553             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR,
    554                     cause.toString());
    555         }
    556     }
    557 
    558     /**
    559      * Send ar.userObj if its a message, which is should be back to originator.
    560      *
    561      * @param dp is the DisconnectParams.
    562      */
    563     private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
    564         if (VDBG) log("NotifyDisconnectCompleted");
    565 
    566         ApnContext alreadySent = null;
    567         String reason = null;
    568 
    569         if (dp != null && dp.mOnCompletedMsg != null) {
    570             // Get the completed message but only use it once
    571             Message msg = dp.mOnCompletedMsg;
    572             dp.mOnCompletedMsg = null;
    573             if (msg.obj instanceof ApnContext) {
    574                 alreadySent = (ApnContext)msg.obj;
    575             }
    576             reason = dp.mReason;
    577             if (VDBG) {
    578                 log(String.format("msg=%s msg.obj=%s", msg.toString(),
    579                     ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
    580             }
    581             AsyncResult.forMessage(msg);
    582             msg.sendToTarget();
    583         }
    584         if (sendAll) {
    585             if (reason == null) {
    586                 reason = DcFailCause.UNKNOWN.toString();
    587             }
    588             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason);
    589         }
    590         if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
    591     }
    592 
    593     /*
    594      * **************************************************************************
    595      * Begin Members and methods owned by DataConnectionTracker but stored
    596      * in a DataConnection because there is one per connection.
    597      * **************************************************************************
    598      */
    599 
    600     /*
    601      * The id is owned by DataConnectionTracker.
    602      */
    603     private int mId;
    604 
    605     /**
    606      * Get the DataConnection ID
    607      */
    608     public int getDataConnectionId() {
    609         return mId;
    610     }
    611 
    612     /*
    613      * **************************************************************************
    614      * End members owned by DataConnectionTracker
    615      * **************************************************************************
    616      */
    617 
    618     /**
    619      * Clear all settings called when entering mInactiveState.
    620      */
    621     private void clearSettings() {
    622         if (DBG) log("clearSettings");
    623 
    624         mCreateTime = -1;
    625         mLastFailTime = -1;
    626         mLastFailCause = DcFailCause.NONE;
    627         mCid = -1;
    628 
    629         mLinkProperties = new LinkProperties();
    630         mApnContexts.clear();
    631         mApnSetting = null;
    632         mDcFailCause = null;
    633     }
    634 
    635     /**
    636      * Process setup completion.
    637      *
    638      * @param ar is the result
    639      * @return SetupResult.
    640      */
    641     private DataCallResponse.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
    642         DataCallResponse response = (DataCallResponse) ar.result;
    643         ConnectionParams cp = (ConnectionParams) ar.userObj;
    644         DataCallResponse.SetupResult result;
    645 
    646         if (cp.mTag != mTag) {
    647             if (DBG) {
    648                 log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag);
    649             }
    650             result = DataCallResponse.SetupResult.ERR_Stale;
    651         } else if (ar.exception != null) {
    652             if (DBG) {
    653                 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
    654                     " response=" + response);
    655             }
    656 
    657             if (ar.exception instanceof CommandException
    658                     && ((CommandException) (ar.exception)).getCommandError()
    659                     == CommandException.Error.RADIO_NOT_AVAILABLE) {
    660                 result = DataCallResponse.SetupResult.ERR_BadCommand;
    661                 result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
    662             } else if ((response == null) || (response.version < 4)) {
    663                 result = DataCallResponse.SetupResult.ERR_GetLastErrorFromRil;
    664             } else {
    665                 result = DataCallResponse.SetupResult.ERR_RilError;
    666                 result.mFailCause = DcFailCause.fromInt(response.status);
    667             }
    668         } else if (response.status != 0) {
    669             result = DataCallResponse.SetupResult.ERR_RilError;
    670             result.mFailCause = DcFailCause.fromInt(response.status);
    671         } else {
    672             if (DBG) log("onSetupConnectionCompleted received DataCallResponse: " + response);
    673             mCid = response.cid;
    674             result = updateLinkProperty(response).setupResult;
    675         }
    676 
    677         return result;
    678     }
    679 
    680     private boolean isDnsOk(String[] domainNameServers) {
    681         if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
    682                 && !mPhone.isDnsCheckDisabled()) {
    683             // Work around a race condition where QMI does not fill in DNS:
    684             // Deactivate PDP and let DataConnectionTracker retry.
    685             // Do not apply the race condition workaround for MMS APN
    686             // if Proxy is an IP-address.
    687             // Otherwise, the default APN will not be restored anymore.
    688             if (!mApnSetting.types[0].equals(PhoneConstants.APN_TYPE_MMS)
    689                 || !isIpAddress(mApnSetting.mmsProxy)) {
    690                 log(String.format(
    691                         "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
    692                         mApnSetting.types[0], PhoneConstants.APN_TYPE_MMS, mApnSetting.mmsProxy,
    693                         isIpAddress(mApnSetting.mmsProxy)));
    694                 return false;
    695             }
    696         }
    697         return true;
    698     }
    699 
    700     private boolean isIpAddress(String address) {
    701         if (address == null) return false;
    702 
    703         return Patterns.IP_ADDRESS.matcher(address).matches();
    704     }
    705 
    706     private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response,
    707             LinkProperties lp) {
    708         // Check if system property dns usable
    709         boolean okToUseSystemPropertyDns = false;
    710         String propertyPrefix = "net." + response.ifname + ".";
    711         String dnsServers[] = new String[2];
    712         dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
    713         dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
    714         okToUseSystemPropertyDns = isDnsOk(dnsServers);
    715 
    716         // set link properties based on data call response
    717         return response.setLinkProperties(lp, okToUseSystemPropertyDns);
    718     }
    719 
    720     /**
    721      * Initialize connection, this will fail if the
    722      * apnSettings are not compatible.
    723      *
    724      * @param cp the Connection paramemters
    725      * @return true if initialization was successful.
    726      */
    727     private boolean initConnection(ConnectionParams cp) {
    728         ApnContext apnContext = cp.mApnContext;
    729         if (mApnSetting == null) {
    730             // Only change apn setting if it isn't set, it will
    731             // only NOT be set only if we're in DcInactiveState.
    732             mApnSetting = apnContext.getApnSetting();
    733         } else if (mApnSetting.canHandleType(apnContext.getApnType())) {
    734             // All is good.
    735         } else {
    736             if (DBG) {
    737                 log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp
    738                         + " dc=" + DataConnection.this);
    739             }
    740             return false;
    741         }
    742         mTag += 1;
    743         mConnectionParams = cp;
    744         mConnectionParams.mTag = mTag;
    745 
    746         if (!mApnContexts.contains(apnContext)) {
    747             mApnContexts.add(apnContext);
    748         }
    749         configureRetry(mApnSetting.canHandleType(PhoneConstants.APN_TYPE_DEFAULT));
    750         mRetryManager.setRetryCount(0);
    751         mRetryManager.setCurMaxRetryCount(mConnectionParams.mInitialMaxRetry);
    752         mRetryManager.setRetryForever(false);
    753 
    754         if (DBG) {
    755             log("initConnection: "
    756                     + " RefCount=" + mApnContexts.size()
    757                     + " mApnList=" + mApnContexts
    758                     + " mConnectionParams=" + mConnectionParams);
    759         }
    760         return true;
    761     }
    762 
    763     /**
    764      * The parent state for all other states.
    765      */
    766     private class DcDefaultState extends State {
    767         @Override
    768         public void enter() {
    769             if (DBG) log("DcDefaultState: enter");
    770 
    771             // Register for DRS or RAT change
    772             mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),
    773                     DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);
    774 
    775             // Add ourselves to the list of data connections
    776             mDcController.addDc(DataConnection.this);
    777         }
    778         @Override
    779         public void exit() {
    780             if (DBG) log("DcDefaultState: exit");
    781 
    782             // Unregister for DRS or RAT change.
    783             mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler());
    784 
    785             // Remove ourselves from the DC lists
    786             mDcController.removeDc(DataConnection.this);
    787 
    788             if (mAc != null) {
    789                 mAc.disconnected();
    790                 mAc = null;
    791             }
    792             mDcRetryAlarmController.dispose();
    793             mDcRetryAlarmController = null;
    794             mApnContexts = null;
    795             mReconnectIntent = null;
    796             mDct = null;
    797             mApnSetting = null;
    798             mPhone = null;
    799             mLinkProperties = null;
    800             mLinkCapabilities = null;
    801             mLastFailCause = null;
    802             mUserData = null;
    803             mDcController = null;
    804             mDcTesterFailBringUpAll = null;
    805         }
    806 
    807         @Override
    808         public boolean processMessage(Message msg) {
    809             boolean retVal = HANDLED;
    810 
    811             if (VDBG) {
    812                 log("DcDefault msg=" + getWhatToString(msg.what)
    813                         + " RefCount=" + mApnContexts.size());
    814             }
    815             switch (msg.what) {
    816                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    817                     if (mAc != null) {
    818                         if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
    819                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    820                                 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
    821                     } else {
    822                         mAc = new AsyncChannel();
    823                         mAc.connected(null, getHandler(), msg.replyTo);
    824                         if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
    825                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    826                                 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
    827                     }
    828                     break;
    829                 }
    830                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    831                     if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
    832                     quit();
    833                     break;
    834                 }
    835                 case DcAsyncChannel.REQ_IS_INACTIVE: {
    836                     boolean val = getIsInactive();
    837                     if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
    838                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_IS_INACTIVE, val ? 1 : 0);
    839                     break;
    840                 }
    841                 case DcAsyncChannel.REQ_GET_CID: {
    842                     int cid = getCid();
    843                     if (VDBG) log("REQ_GET_CID  cid=" + cid);
    844                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_CID, cid);
    845                     break;
    846                 }
    847                 case DcAsyncChannel.REQ_GET_APNSETTING: {
    848                     ApnSetting apnSetting = getApnSetting();
    849                     if (VDBG) log("REQ_GET_APNSETTING  mApnSetting=" + apnSetting);
    850                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_APNSETTING, apnSetting);
    851                     break;
    852                 }
    853                 case DcAsyncChannel.REQ_GET_LINK_PROPERTIES: {
    854                     LinkProperties lp = getCopyLinkProperties();
    855                     if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
    856                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_PROPERTIES, lp);
    857                     break;
    858                 }
    859                 case DcAsyncChannel.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
    860                     ProxyProperties proxy = (ProxyProperties) msg.obj;
    861                     if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
    862                     setLinkPropertiesHttpProxy(proxy);
    863                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
    864                     break;
    865                 }
    866                 case DcAsyncChannel.REQ_GET_LINK_CAPABILITIES: {
    867                     LinkCapabilities lc = getCopyLinkCapabilities();
    868                     if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
    869                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_CAPABILITIES, lc);
    870                     break;
    871                 }
    872                 case DcAsyncChannel.REQ_RESET:
    873                     if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
    874                     transitionTo(mInactiveState);
    875                     break;
    876                 case EVENT_CONNECT:
    877                     if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
    878                     ConnectionParams cp = (ConnectionParams) msg.obj;
    879                     notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false);
    880                     break;
    881 
    882                 case EVENT_DISCONNECT:
    883                     if (DBG) {
    884                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount="
    885                                 + mApnContexts.size());
    886                     }
    887                     deferMessage(msg);
    888                     break;
    889 
    890                 case EVENT_DISCONNECT_ALL:
    891                     if (DBG) {
    892                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount="
    893                                 + mApnContexts.size());
    894                     }
    895                     deferMessage(msg);
    896                     break;
    897 
    898                 case EVENT_TEAR_DOWN_NOW:
    899                     if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW");
    900                     mPhone.mCi.deactivateDataCall(mCid, 0,  null);
    901                     break;
    902 
    903                 case EVENT_LOST_CONNECTION:
    904                     if (DBG) {
    905                         String s = "DcDefaultState ignore EVENT_LOST_CONNECTION"
    906                             + " tag=" + msg.arg1 + ":mTag=" + mTag;
    907                         logAndAddLogRec(s);
    908                     }
    909                     break;
    910 
    911                 case EVENT_RETRY_CONNECTION:
    912                     if (DBG) {
    913                         String s = "DcDefaultState ignore EVENT_RETRY_CONNECTION"
    914                                 + " tag=" + msg.arg1 + ":mTag=" + mTag;
    915                         logAndAddLogRec(s);
    916                     }
    917                     break;
    918 
    919                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
    920                     AsyncResult ar = (AsyncResult)msg.obj;
    921                     Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
    922                     mDataRegState = drsRatPair.first;
    923                     mRilRat = drsRatPair.second;
    924                     if (DBG) {
    925                         log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
    926                                 + " drs=" + mDataRegState
    927                                 + " mRilRat=" + mRilRat);
    928                     }
    929                     break;
    930 
    931                 default:
    932                     if (DBG) {
    933                         log("DcDefaultState: shouldn't happen but ignore msg.what="
    934                                 + getWhatToString(msg.what));
    935                     }
    936                     break;
    937             }
    938 
    939             return retVal;
    940         }
    941     }
    942     private DcDefaultState mDefaultState = new DcDefaultState();
    943 
    944     /**
    945      * The state machine is inactive and expects a EVENT_CONNECT.
    946      */
    947     private class DcInactiveState extends State {
    948         // Inform all contexts we've failed connecting
    949         public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) {
    950             if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
    951             mConnectionParams = cp;
    952             mDisconnectParams = null;
    953             mDcFailCause = cause;
    954         }
    955 
    956         // Inform all contexts we've failed disconnected
    957         public void setEnterNotificationParams(DisconnectParams dp) {
    958             if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
    959             mConnectionParams = null;
    960             mDisconnectParams = dp;
    961             mDcFailCause = DcFailCause.NONE;
    962         }
    963 
    964         // Inform all contexts of the failure cause
    965         public void setEnterNotificationParams(DcFailCause cause) {
    966             mConnectionParams = null;
    967             mDisconnectParams = null;
    968             mDcFailCause = cause;
    969         }
    970 
    971         @Override
    972         public void enter() {
    973             mTag += 1;
    974             if (DBG) log("DcInactiveState: enter() mTag=" + mTag);
    975 
    976             if (mConnectionParams != null) {
    977                 if (DBG) {
    978                     log("DcInactiveState: enter notifyConnectCompleted +ALL failCause="
    979                             + mDcFailCause);
    980                 }
    981                 notifyConnectCompleted(mConnectionParams, mDcFailCause, true);
    982             }
    983             if (mDisconnectParams != null) {
    984                 if (DBG) {
    985                     log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause="
    986                             + mDcFailCause);
    987                 }
    988                 notifyDisconnectCompleted(mDisconnectParams, true);
    989             }
    990             if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) {
    991                 if (DBG) {
    992                     log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
    993                             + mDcFailCause);
    994                 }
    995                 notifyAllDisconnectCompleted(mDcFailCause);
    996             }
    997 
    998             // Remove ourselves from cid mapping, before clearSettings
    999             mDcController.removeActiveDcByCid(DataConnection.this);
   1000 
   1001             clearSettings();
   1002         }
   1003 
   1004         @Override
   1005         public void exit() {
   1006         }
   1007 
   1008         @Override
   1009         public boolean processMessage(Message msg) {
   1010             boolean retVal;
   1011 
   1012             switch (msg.what) {
   1013                 case DcAsyncChannel.REQ_RESET:
   1014                     if (DBG) {
   1015                         log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
   1016                     }
   1017                     retVal = HANDLED;
   1018                     break;
   1019 
   1020                 case EVENT_CONNECT:
   1021                     if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
   1022                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1023                     if (initConnection(cp)) {
   1024                         onConnect(mConnectionParams);
   1025                         transitionTo(mActivatingState);
   1026                     } else {
   1027                         if (DBG) {
   1028                             log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
   1029                         }
   1030                         notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
   1031                                 false);
   1032                     }
   1033                     retVal = HANDLED;
   1034                     break;
   1035 
   1036                 case EVENT_DISCONNECT:
   1037                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
   1038                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
   1039                     retVal = HANDLED;
   1040                     break;
   1041 
   1042                 case EVENT_DISCONNECT_ALL:
   1043                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
   1044                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
   1045                     retVal = HANDLED;
   1046                     break;
   1047 
   1048                 default:
   1049                     if (VDBG) {
   1050                         log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what));
   1051                     }
   1052                     retVal = NOT_HANDLED;
   1053                     break;
   1054             }
   1055             return retVal;
   1056         }
   1057     }
   1058     private DcInactiveState mInactiveState = new DcInactiveState();
   1059 
   1060     /**
   1061      * The state machine is retrying and expects a EVENT_RETRY_CONNECTION.
   1062      */
   1063     private class DcRetryingState extends State {
   1064         @Override
   1065         public void enter() {
   1066             if ((mConnectionParams.mRilRat != mRilRat)
   1067                     || (mDataRegState != ServiceState.STATE_IN_SERVICE)){
   1068                 // RAT has changed or we're not in service so don't even begin retrying.
   1069                 if (DBG) {
   1070                     String s = "DcRetryingState: enter() not retrying rat changed"
   1071                         + ", mConnectionParams.mRilRat=" + mConnectionParams.mRilRat
   1072                         + " != mRilRat:" + mRilRat
   1073                         + " transitionTo(mInactiveState)";
   1074                     logAndAddLogRec(s);
   1075                 }
   1076                 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1077                 transitionTo(mInactiveState);
   1078             } else {
   1079                 if (DBG) {
   1080                     log("DcRetryingState: enter() mTag=" + mTag
   1081                         + ", call notifyAllOfDisconnectDcRetrying lostConnection");
   1082                 }
   1083 
   1084                 notifyAllOfDisconnectDcRetrying(Phone.REASON_LOST_DATA_CONNECTION);
   1085 
   1086                 // Remove ourselves from cid mapping
   1087                 mDcController.removeActiveDcByCid(DataConnection.this);
   1088                 mCid = -1;
   1089             }
   1090         }
   1091 
   1092         @Override
   1093         public boolean processMessage(Message msg) {
   1094             boolean retVal;
   1095 
   1096             switch (msg.what) {
   1097                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
   1098                     AsyncResult ar = (AsyncResult)msg.obj;
   1099                     Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
   1100                     int drs = drsRatPair.first;
   1101                     int rat = drsRatPair.second;
   1102                     if ((rat == mRilRat) && (drs == mDataRegState)) {
   1103                         if (DBG) {
   1104                             log("DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
   1105                                     + " strange no change in drs=" + drs
   1106                                     + " rat=" + rat + " ignoring");
   1107                         }
   1108                     } else {
   1109                         // We've lost the connection and we're retrying but DRS or RAT changed
   1110                         // so we may never succeed, might as well give up.
   1111                         mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1112                         deferMessage(msg);
   1113                         transitionTo(mInactiveState);
   1114 
   1115                         if (DBG) {
   1116                             String s = "DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
   1117                                     + " giving up changed from " + mRilRat
   1118                                     + " to rat=" + rat
   1119                                     + " or drs changed from " + mDataRegState + " to drs=" + drs;
   1120                             logAndAddLogRec(s);
   1121                         }
   1122                         mDataRegState = drs;
   1123                         mRilRat = rat;
   1124                     }
   1125                     retVal = HANDLED;
   1126                     break;
   1127 
   1128                 case EVENT_RETRY_CONNECTION: {
   1129                     if (msg.arg1 == mTag) {
   1130                         mRetryManager.increaseRetryCount();
   1131                         if (DBG) {
   1132                             log("DcRetryingState EVENT_RETRY_CONNECTION"
   1133                                     + " RetryCount=" +  mRetryManager.getRetryCount()
   1134                                     + " mConnectionParams=" + mConnectionParams);
   1135                         }
   1136                         onConnect(mConnectionParams);
   1137                         transitionTo(mActivatingState);
   1138                     } else {
   1139                         if (DBG) {
   1140                             log("DcRetryingState stale EVENT_RETRY_CONNECTION"
   1141                                     + " tag:" + msg.arg1 + " != mTag:" + mTag);
   1142                         }
   1143                     }
   1144                     retVal = HANDLED;
   1145                     break;
   1146                 }
   1147                 case DcAsyncChannel.REQ_RESET: {
   1148                     if (DBG) {
   1149                         log("DcRetryingState: msg.what=RSP_RESET, ignore we're already reset");
   1150                     }
   1151                     mInactiveState.setEnterNotificationParams(mConnectionParams,
   1152                             DcFailCause.RESET_BY_FRAMEWORK);
   1153                     transitionTo(mInactiveState);
   1154                     retVal = HANDLED;
   1155                     break;
   1156                 }
   1157                 case EVENT_CONNECT: {
   1158                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1159                     if (DBG) {
   1160                         log("DcRetryingState: msg.what=EVENT_CONNECT"
   1161                                 + " RefCount=" + mApnContexts.size() + " cp=" + cp
   1162                                 + " mConnectionParams=" + mConnectionParams);
   1163                     }
   1164                     if (initConnection(cp)) {
   1165                         onConnect(mConnectionParams);
   1166                         transitionTo(mActivatingState);
   1167                     } else {
   1168                         if (DBG) {
   1169                             log("DcRetryingState: msg.what=EVENT_CONNECT initConnection failed");
   1170                         }
   1171                         notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
   1172                                 false);
   1173                     }
   1174                     retVal = HANDLED;
   1175                     break;
   1176                 }
   1177                 case EVENT_DISCONNECT: {
   1178                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1179 
   1180                     if (mApnContexts.remove(dp.mApnContext) && mApnContexts.size() == 0) {
   1181                         if (DBG) {
   1182                             log("DcRetryingState msg.what=EVENT_DISCONNECT " + " RefCount="
   1183                                     + mApnContexts.size() + " dp=" + dp);
   1184                         }
   1185                         mInactiveState.setEnterNotificationParams(dp);
   1186                         transitionTo(mInactiveState);
   1187                     } else {
   1188                         if (DBG) log("DcRetryingState: msg.what=EVENT_DISCONNECT");
   1189                         notifyDisconnectCompleted(dp, false);
   1190                     }
   1191                     retVal = HANDLED;
   1192                     break;
   1193                 }
   1194                 case EVENT_DISCONNECT_ALL: {
   1195                     if (DBG) {
   1196                         log("DcRetryingState msg.what=EVENT_DISCONNECT/DISCONNECT_ALL "
   1197                                 + "RefCount=" + mApnContexts.size());
   1198                     }
   1199                     mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1200                     deferMessage(msg);
   1201                     transitionTo(mInactiveState);
   1202                     retVal = HANDLED;
   1203                     break;
   1204                 }
   1205                 default: {
   1206                     if (VDBG) {
   1207                         log("DcRetryingState nothandled msg.what=" + getWhatToString(msg.what));
   1208                     }
   1209                     retVal = NOT_HANDLED;
   1210                     break;
   1211                 }
   1212             }
   1213             return retVal;
   1214         }
   1215     }
   1216     private DcRetryingState mRetryingState = new DcRetryingState();
   1217 
   1218     /**
   1219      * The state machine is activating a connection.
   1220      */
   1221     private class DcActivatingState extends State {
   1222         @Override
   1223         public boolean processMessage(Message msg) {
   1224             boolean retVal;
   1225             AsyncResult ar;
   1226             ConnectionParams cp;
   1227 
   1228             if (DBG) log("DcActivatingState: msg=" + msgToString(msg));
   1229             switch (msg.what) {
   1230                 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
   1231                 case EVENT_CONNECT:
   1232                     // Activating can't process until we're done.
   1233                     deferMessage(msg);
   1234                     retVal = HANDLED;
   1235                     break;
   1236 
   1237                 case EVENT_SETUP_DATA_CONNECTION_DONE:
   1238                     ar = (AsyncResult) msg.obj;
   1239                     cp = (ConnectionParams) ar.userObj;
   1240 
   1241                     DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);
   1242                     if (result != DataCallResponse.SetupResult.ERR_Stale) {
   1243                         if (mConnectionParams != cp) {
   1244                             loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams
   1245                                     + " != cp:" + cp);
   1246                         }
   1247                     }
   1248                     if (DBG) {
   1249                         log("DcActivatingState onSetupConnectionCompleted result=" + result
   1250                                 + " dc=" + DataConnection.this);
   1251                     }
   1252                     switch (result) {
   1253                         case SUCCESS:
   1254                             // All is well
   1255                             mDcFailCause = DcFailCause.NONE;
   1256                             transitionTo(mActiveState);
   1257                             break;
   1258                         case ERR_BadCommand:
   1259                             // Vendor ril rejected the command and didn't connect.
   1260                             // Transition to inactive but send notifications after
   1261                             // we've entered the mInactive state.
   1262                             mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1263                             transitionTo(mInactiveState);
   1264                             break;
   1265                         case ERR_UnacceptableParameter:
   1266                             // The addresses given from the RIL are bad
   1267                             tearDownData(cp);
   1268                             transitionTo(mDisconnectingErrorCreatingConnection);
   1269                             break;
   1270                         case ERR_GetLastErrorFromRil:
   1271                             // Request failed and this is an old RIL
   1272                             mPhone.mCi.getLastDataCallFailCause(
   1273                                     obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
   1274                             break;
   1275                         case ERR_RilError:
   1276                             int delay = mDcRetryAlarmController.getSuggestedRetryTime(
   1277                                                                     DataConnection.this, ar);
   1278                             if (DBG) {
   1279                                 log("DcActivatingState: ERR_RilError "
   1280                                         + " delay=" + delay
   1281                                         + " isRetryNeeded=" + mRetryManager.isRetryNeeded()
   1282                                         + " result=" + result
   1283                                         + " result.isRestartRadioFail=" +
   1284                                                 result.mFailCause.isRestartRadioFail()
   1285                                         + " result.isPermanentFail=" +
   1286                                                 result.mFailCause.isPermanentFail());
   1287                             }
   1288                             if (result.mFailCause.isRestartRadioFail()) {
   1289                                 if (DBG) log("DcActivatingState: ERR_RilError restart radio");
   1290                                 mDct.sendRestartRadio();
   1291                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1292                                 transitionTo(mInactiveState);
   1293                             } else if (result.mFailCause.isPermanentFail()) {
   1294                                 if (DBG) log("DcActivatingState: ERR_RilError perm error");
   1295                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1296                                 transitionTo(mInactiveState);
   1297                             } else if (delay >= 0) {
   1298                                 if (DBG) log("DcActivatingState: ERR_RilError retry");
   1299                                 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION,
   1300                                                             mTag, delay);
   1301                                 transitionTo(mRetryingState);
   1302                             } else {
   1303                                 if (DBG) log("DcActivatingState: ERR_RilError no retry");
   1304                                 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
   1305                                 transitionTo(mInactiveState);
   1306                             }
   1307                             break;
   1308                         case ERR_Stale:
   1309                             loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE"
   1310                                     + " tag:" + cp.mTag + " != mTag:" + mTag);
   1311                             break;
   1312                         default:
   1313                             throw new RuntimeException("Unknown SetupResult, should not happen");
   1314                     }
   1315                     retVal = HANDLED;
   1316                     break;
   1317 
   1318                 case EVENT_GET_LAST_FAIL_DONE:
   1319                     ar = (AsyncResult) msg.obj;
   1320                     cp = (ConnectionParams) ar.userObj;
   1321                     if (cp.mTag == mTag) {
   1322                         if (mConnectionParams != cp) {
   1323                             loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams
   1324                                     + " != cp:" + cp);
   1325                         }
   1326 
   1327                         DcFailCause cause = DcFailCause.UNKNOWN;
   1328 
   1329                         if (ar.exception == null) {
   1330                             int rilFailCause = ((int[]) (ar.result))[0];
   1331                             cause = DcFailCause.fromInt(rilFailCause);
   1332                             if (cause == DcFailCause.NONE) {
   1333                                 if (DBG) {
   1334                                     log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
   1335                                             + " BAD: error was NONE, change to UNKNOWN");
   1336                                 }
   1337                                 cause = DcFailCause.UNKNOWN;
   1338                             }
   1339                         }
   1340                         mDcFailCause = cause;
   1341 
   1342                         int retryDelay = mRetryManager.getRetryTimer();
   1343                         if (DBG) {
   1344                             log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
   1345                                     + " cause=" + cause
   1346                                     + " retryDelay=" + retryDelay
   1347                                     + " isRetryNeeded=" + mRetryManager.isRetryNeeded()
   1348                                     + " dc=" + DataConnection.this);
   1349                         }
   1350                         if (cause.isRestartRadioFail()) {
   1351                             if (DBG) {
   1352                                 log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE"
   1353                                         + " restart radio");
   1354                             }
   1355                             mDct.sendRestartRadio();
   1356                             mInactiveState.setEnterNotificationParams(cp, cause);
   1357                             transitionTo(mInactiveState);
   1358                         } else if (cause.isPermanentFail()) {
   1359                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE perm er");
   1360                             mInactiveState.setEnterNotificationParams(cp, cause);
   1361                             transitionTo(mInactiveState);
   1362                         } else if ((retryDelay >= 0) && (mRetryManager.isRetryNeeded())) {
   1363                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE retry");
   1364                             mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
   1365                                                             retryDelay);
   1366                             transitionTo(mRetryingState);
   1367                         } else {
   1368                             if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE no retry");
   1369                             mInactiveState.setEnterNotificationParams(cp, cause);
   1370                             transitionTo(mInactiveState);
   1371                         }
   1372                     } else {
   1373                         loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE"
   1374                                 + " tag:" + cp.mTag + " != mTag:" + mTag);
   1375                     }
   1376 
   1377                     retVal = HANDLED;
   1378                     break;
   1379 
   1380                 default:
   1381                     if (VDBG) {
   1382                         log("DcActivatingState not handled msg.what=" +
   1383                                 getWhatToString(msg.what) + " RefCount=" + mApnContexts.size());
   1384                     }
   1385                     retVal = NOT_HANDLED;
   1386                     break;
   1387             }
   1388             return retVal;
   1389         }
   1390     }
   1391     private DcActivatingState mActivatingState = new DcActivatingState();
   1392 
   1393     /**
   1394      * The state machine is connected, expecting an EVENT_DISCONNECT.
   1395      */
   1396     private class DcActiveState extends State {
   1397         @Override public void enter() {
   1398             if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
   1399 
   1400             if (mRetryManager.getRetryCount() != 0) {
   1401                 log("DcActiveState: connected after retrying call notifyAllOfConnected");
   1402                 mRetryManager.setRetryCount(0);
   1403             }
   1404             // If we were retrying there maybe more than one, otherwise they'll only be one.
   1405             notifyAllOfConnected(Phone.REASON_CONNECTED);
   1406 
   1407             // If the EVENT_CONNECT set the current max retry restore it here
   1408             // if it didn't then this is effectively a NOP.
   1409             mRetryManager.restoreCurMaxRetryCount();
   1410             mDcController.addActiveDcByCid(DataConnection.this);
   1411         }
   1412 
   1413         @Override
   1414         public void exit() {
   1415             if (DBG) log("DcActiveState: exit dc=" + this);
   1416         }
   1417 
   1418         @Override
   1419         public boolean processMessage(Message msg) {
   1420             boolean retVal;
   1421 
   1422             switch (msg.what) {
   1423                 case EVENT_CONNECT: {
   1424                     ConnectionParams cp = (ConnectionParams) msg.obj;
   1425                     if (DBG) {
   1426                         log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this);
   1427                     }
   1428                     if (mApnContexts.contains(cp.mApnContext)) {
   1429                         log("DcActiveState ERROR already added apnContext=" + cp.mApnContext);
   1430                     } else {
   1431                         mApnContexts.add(cp.mApnContext);
   1432                         if (DBG) {
   1433                             log("DcActiveState msg.what=EVENT_CONNECT RefCount="
   1434                                     + mApnContexts.size());
   1435                         }
   1436                     }
   1437                     notifyConnectCompleted(cp, DcFailCause.NONE, false);
   1438                     retVal = HANDLED;
   1439                     break;
   1440                 }
   1441                 case EVENT_DISCONNECT: {
   1442                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1443                     if (DBG) {
   1444                         log("DcActiveState: EVENT_DISCONNECT dp=" + dp
   1445                                 + " dc=" + DataConnection.this);
   1446                     }
   1447                     if (mApnContexts.contains(dp.mApnContext)) {
   1448                         if (DBG) {
   1449                             log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
   1450                                     + mApnContexts.size());
   1451                         }
   1452 
   1453                         if (mApnContexts.size() == 1) {
   1454                             mApnContexts.clear();
   1455                             mDisconnectParams = dp;
   1456                             mConnectionParams = null;
   1457                             dp.mTag = mTag;
   1458                             tearDownData(dp);
   1459                             transitionTo(mDisconnectingState);
   1460                         } else {
   1461                             mApnContexts.remove(dp.mApnContext);
   1462                             notifyDisconnectCompleted(dp, false);
   1463                         }
   1464                     } else {
   1465                         log("DcActiveState ERROR no such apnContext=" + dp.mApnContext
   1466                                 + " in this dc=" + DataConnection.this);
   1467                         notifyDisconnectCompleted(dp, false);
   1468                     }
   1469                     retVal = HANDLED;
   1470                     break;
   1471                 }
   1472                 case EVENT_DISCONNECT_ALL: {
   1473                     if (DBG) {
   1474                         log("DcActiveState EVENT_DISCONNECT clearing apn contexts,"
   1475                                 + " dc=" + DataConnection.this);
   1476                     }
   1477                     mApnContexts.clear();
   1478                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1479                     mDisconnectParams = dp;
   1480                     mConnectionParams = null;
   1481                     dp.mTag = mTag;
   1482                     tearDownData(dp);
   1483                     transitionTo(mDisconnectingState);
   1484                     retVal = HANDLED;
   1485                     break;
   1486                 }
   1487                 case EVENT_LOST_CONNECTION: {
   1488                     if (DBG) {
   1489                         log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this);
   1490                     }
   1491                     if (mRetryManager.isRetryNeeded()) {
   1492                         // We're going to retry
   1493                         int delayMillis = mRetryManager.getRetryTimer();
   1494                         if (DBG) {
   1495                             log("DcActiveState EVENT_LOST_CONNECTION startRetryAlarm"
   1496                                     + " mTag=" + mTag + " delay=" + delayMillis + "ms");
   1497                         }
   1498                         mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag,
   1499                                 delayMillis);
   1500                         transitionTo(mRetryingState);
   1501                     } else {
   1502                         mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
   1503                         transitionTo(mInactiveState);
   1504                     }
   1505                     retVal = HANDLED;
   1506                     break;
   1507                 }
   1508                 default:
   1509                     if (VDBG) {
   1510                         log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
   1511                     }
   1512                     retVal = NOT_HANDLED;
   1513                     break;
   1514             }
   1515             return retVal;
   1516         }
   1517     }
   1518     private DcActiveState mActiveState = new DcActiveState();
   1519 
   1520     /**
   1521      * The state machine is disconnecting.
   1522      */
   1523     private class DcDisconnectingState extends State {
   1524         @Override
   1525         public boolean processMessage(Message msg) {
   1526             boolean retVal;
   1527 
   1528             switch (msg.what) {
   1529                 case EVENT_CONNECT:
   1530                     if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
   1531                             + mApnContexts.size());
   1532                     deferMessage(msg);
   1533                     retVal = HANDLED;
   1534                     break;
   1535 
   1536                 case EVENT_DEACTIVATE_DONE:
   1537                     if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount="
   1538                             + mApnContexts.size());
   1539                     AsyncResult ar = (AsyncResult) msg.obj;
   1540                     DisconnectParams dp = (DisconnectParams) ar.userObj;
   1541                     if (dp.mTag == mTag) {
   1542                         // Transition to inactive but send notifications after
   1543                         // we've entered the mInactive state.
   1544                         mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
   1545                         transitionTo(mInactiveState);
   1546                     } else {
   1547                         if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE"
   1548                                 + " dp.tag=" + dp.mTag + " mTag=" + mTag);
   1549                     }
   1550                     retVal = HANDLED;
   1551                     break;
   1552 
   1553                 default:
   1554                     if (VDBG) {
   1555                         log("DcDisconnectingState not handled msg.what="
   1556                                 + getWhatToString(msg.what));
   1557                     }
   1558                     retVal = NOT_HANDLED;
   1559                     break;
   1560             }
   1561             return retVal;
   1562         }
   1563     }
   1564     private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
   1565 
   1566     /**
   1567      * The state machine is disconnecting after an creating a connection.
   1568      */
   1569     private class DcDisconnectionErrorCreatingConnection extends State {
   1570         @Override
   1571         public boolean processMessage(Message msg) {
   1572             boolean retVal;
   1573 
   1574             switch (msg.what) {
   1575                 case EVENT_DEACTIVATE_DONE:
   1576                     AsyncResult ar = (AsyncResult) msg.obj;
   1577                     ConnectionParams cp = (ConnectionParams) ar.userObj;
   1578                     if (cp.mTag == mTag) {
   1579                         if (DBG) {
   1580                             log("DcDisconnectionErrorCreatingConnection" +
   1581                                 " msg.what=EVENT_DEACTIVATE_DONE");
   1582                         }
   1583 
   1584                         // Transition to inactive but send notifications after
   1585                         // we've entered the mInactive state.
   1586                         mInactiveState.setEnterNotificationParams(cp,
   1587                                 DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
   1588                         transitionTo(mInactiveState);
   1589                     } else {
   1590                         if (DBG) {
   1591                             log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE"
   1592                                     + " dp.tag=" + cp.mTag + ", mTag=" + mTag);
   1593                         }
   1594                     }
   1595                     retVal = HANDLED;
   1596                     break;
   1597 
   1598                 default:
   1599                     if (VDBG) {
   1600                         log("DcDisconnectionErrorCreatingConnection not handled msg.what="
   1601                                 + getWhatToString(msg.what));
   1602                     }
   1603                     retVal = NOT_HANDLED;
   1604                     break;
   1605             }
   1606             return retVal;
   1607         }
   1608     }
   1609     private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
   1610                 new DcDisconnectionErrorCreatingConnection();
   1611 
   1612     // ******* "public" interface
   1613 
   1614     /**
   1615      * Used for testing purposes.
   1616      */
   1617     /* package */ void tearDownNow() {
   1618         if (DBG) log("tearDownNow()");
   1619         sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW));
   1620     }
   1621 
   1622     /**
   1623      * @return the string for msg.what as our info.
   1624      */
   1625     @Override
   1626     protected String getWhatToString(int what) {
   1627         return cmdToString(what);
   1628     }
   1629 
   1630     private static String msgToString(Message msg) {
   1631         String retVal;
   1632         if (msg == null) {
   1633             retVal = "null";
   1634         } else {
   1635             StringBuilder   b = new StringBuilder();
   1636 
   1637             b.append("{what=");
   1638             b.append(cmdToString(msg.what));
   1639 
   1640             b.append(" when=");
   1641             TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b);
   1642 
   1643             if (msg.arg1 != 0) {
   1644                 b.append(" arg1=");
   1645                 b.append(msg.arg1);
   1646             }
   1647 
   1648             if (msg.arg2 != 0) {
   1649                 b.append(" arg2=");
   1650                 b.append(msg.arg2);
   1651             }
   1652 
   1653             if (msg.obj != null) {
   1654                 b.append(" obj=");
   1655                 b.append(msg.obj);
   1656             }
   1657 
   1658             b.append(" target=");
   1659             b.append(msg.getTarget());
   1660 
   1661             b.append(" replyTo=");
   1662             b.append(msg.replyTo);
   1663 
   1664             b.append("}");
   1665 
   1666             retVal = b.toString();
   1667         }
   1668         return retVal;
   1669     }
   1670 
   1671     static void slog(String s) {
   1672         Rlog.d("DC", s);
   1673     }
   1674 
   1675     /**
   1676      * Log with debug
   1677      *
   1678      * @param s is string log
   1679      */
   1680     @Override
   1681     protected void log(String s) {
   1682         Rlog.d(getName(), s);
   1683     }
   1684 
   1685     /**
   1686      * Log with debug attribute
   1687      *
   1688      * @param s is string log
   1689      */
   1690     @Override
   1691     protected void logd(String s) {
   1692         Rlog.d(getName(), s);
   1693     }
   1694 
   1695     /**
   1696      * Log with verbose attribute
   1697      *
   1698      * @param s is string log
   1699      */
   1700     @Override
   1701     protected void logv(String s) {
   1702         Rlog.v(getName(), s);
   1703     }
   1704 
   1705     /**
   1706      * Log with info attribute
   1707      *
   1708      * @param s is string log
   1709      */
   1710     @Override
   1711     protected void logi(String s) {
   1712         Rlog.i(getName(), s);
   1713     }
   1714 
   1715     /**
   1716      * Log with warning attribute
   1717      *
   1718      * @param s is string log
   1719      */
   1720     @Override
   1721     protected void logw(String s) {
   1722         Rlog.w(getName(), s);
   1723     }
   1724 
   1725     /**
   1726      * Log with error attribute
   1727      *
   1728      * @param s is string log
   1729      */
   1730     @Override
   1731     protected void loge(String s) {
   1732         Rlog.e(getName(), s);
   1733     }
   1734 
   1735     /**
   1736      * Log with error attribute
   1737      *
   1738      * @param s is string log
   1739      * @param e is a Throwable which logs additional information.
   1740      */
   1741     @Override
   1742     protected void loge(String s, Throwable e) {
   1743         Rlog.e(getName(), s, e);
   1744     }
   1745 
   1746     /** Doesn't print mApnList of ApnContext's which would be recursive */
   1747     public String toStringSimple() {
   1748         return getName() + ": State=" + getCurrentState().getName()
   1749                 + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size()
   1750                 + " mCid=" + mCid + " mCreateTime=" + mCreateTime
   1751                 + " mLastastFailTime=" + mLastFailTime
   1752                 + " mLastFailCause=" + mLastFailCause
   1753                 + " mTag=" + mTag
   1754                 + " mRetryManager=" + mRetryManager
   1755                 + " mLinkProperties=" + mLinkProperties
   1756                 + " mLinkCapabilities=" + mLinkCapabilities;
   1757     }
   1758 
   1759     @Override
   1760     public String toString() {
   1761         return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}";
   1762     }
   1763 
   1764     /**
   1765      * Dump the current state.
   1766      *
   1767      * @param fd
   1768      * @param pw
   1769      * @param args
   1770      */
   1771     @Override
   1772     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1773         pw.print("DataConnection ");
   1774         super.dump(fd, pw, args);
   1775         pw.println(" mApnContexts.size=" + mApnContexts.size());
   1776         pw.println(" mApnContexts=" + mApnContexts);
   1777         pw.flush();
   1778         pw.println(" mDataConnectionTracker=" + mDct);
   1779         pw.println(" mApnSetting=" + mApnSetting);
   1780         pw.println(" mTag=" + mTag);
   1781         pw.println(" mCid=" + mCid);
   1782         pw.println(" mRetryManager=" + mRetryManager);
   1783         pw.println(" mConnectionParams=" + mConnectionParams);
   1784         pw.println(" mDisconnectParams=" + mDisconnectParams);
   1785         pw.println(" mDcFailCause=" + mDcFailCause);
   1786         pw.flush();
   1787         pw.println(" mPhone=" + mPhone);
   1788         pw.flush();
   1789         pw.println(" mLinkProperties=" + mLinkProperties);
   1790         pw.flush();
   1791         pw.println(" mDataRegState=" + mDataRegState);
   1792         pw.println(" mRilRat=" + mRilRat);
   1793         pw.println(" mLinkCapabilities=" + mLinkCapabilities);
   1794         pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
   1795         pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
   1796         pw.println(" mLastFailCause=" + mLastFailCause);
   1797         pw.flush();
   1798         pw.println(" mUserData=" + mUserData);
   1799         pw.println(" mInstanceNumber=" + mInstanceNumber);
   1800         pw.println(" mAc=" + mAc);
   1801         pw.println(" mDcRetryAlarmController=" + mDcRetryAlarmController);
   1802         pw.flush();
   1803     }
   1804 }
   1805