Home | History | Annotate | Download | only in telephony
      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;
     18 
     19 
     20 import com.android.internal.telephony.DataCallState.SetupResult;
     21 import com.android.internal.util.AsyncChannel;
     22 import com.android.internal.util.Protocol;
     23 import com.android.internal.util.State;
     24 import com.android.internal.util.StateMachine;
     25 
     26 import android.app.PendingIntent;
     27 import android.net.LinkCapabilities;
     28 import android.net.LinkProperties;
     29 import android.net.ProxyProperties;
     30 import android.os.AsyncResult;
     31 import android.os.Message;
     32 import android.os.SystemProperties;
     33 import android.text.TextUtils;
     34 import android.util.TimeUtils;
     35 
     36 import java.io.FileDescriptor;
     37 import java.io.PrintWriter;
     38 import java.util.ArrayList;
     39 import java.util.Calendar;
     40 import java.util.HashMap;
     41 import java.util.List;
     42 
     43 /**
     44  * {@hide}
     45  *
     46  * DataConnection StateMachine.
     47  *
     48  * This is an abstract base class for representing a single data connection.
     49  * Instances of this class such as <code>CdmaDataConnection</code> and
     50  * <code>GsmDataConnection</code>, * represent a connection via the cellular network.
     51  * There may be multiple data connections and all of them are managed by the
     52  * <code>DataConnectionTracker</code>.
     53  *
     54  * Instances are asynchronous state machines and have two primary entry points
     55  * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
     56  * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
     57  * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
     58  * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
     59  * If an error <code>AsyncResult.result = FailCause</code> and
     60  * <code>AsyncResult.exception = new Exception()</code>.
     61  *
     62  * The other public methods are provided for debugging.
     63  */
     64 public abstract class DataConnection extends StateMachine {
     65     protected static final boolean DBG = true;
     66     protected static final boolean VDBG = false;
     67 
     68     protected static Object mCountLock = new Object();
     69     protected static int mCount;
     70     protected AsyncChannel mAc;
     71 
     72     protected List<ApnContext> mApnList = null;
     73     PendingIntent mReconnectIntent = null;
     74 
     75     private DataConnectionTracker mDataConnectionTracker = null;
     76 
     77     /**
     78      * Used internally for saving connecting parameters.
     79      */
     80     protected static class ConnectionParams {
     81         public ConnectionParams(ApnSetting apn, Message onCompletedMsg) {
     82             this.apn = apn;
     83             this.onCompletedMsg = onCompletedMsg;
     84         }
     85 
     86         public int tag;
     87         public ApnSetting apn;
     88         public Message onCompletedMsg;
     89     }
     90 
     91     /**
     92      * Used internally for saving disconnecting parameters.
     93      */
     94     protected static class DisconnectParams {
     95         public DisconnectParams(String reason, Message onCompletedMsg) {
     96             this.reason = reason;
     97             this.onCompletedMsg = onCompletedMsg;
     98         }
     99         public int tag;
    100         public String reason;
    101         public Message onCompletedMsg;
    102     }
    103 
    104     /**
    105      * Returned as the reason for a connection failure as defined
    106      * by RIL_DataCallFailCause in ril.h and some local errors.
    107      */
    108     public enum FailCause {
    109         NONE(0),
    110 
    111         // This series of errors as specified by the standards
    112         // specified in ril.h
    113         OPERATOR_BARRED(0x08),
    114         INSUFFICIENT_RESOURCES(0x1A),
    115         MISSING_UNKNOWN_APN(0x1B),
    116         UNKNOWN_PDP_ADDRESS_TYPE(0x1C),
    117         USER_AUTHENTICATION(0x1D),
    118         ACTIVATION_REJECT_GGSN(0x1E),
    119         ACTIVATION_REJECT_UNSPECIFIED(0x1F),
    120         SERVICE_OPTION_NOT_SUPPORTED(0x20),
    121         SERVICE_OPTION_NOT_SUBSCRIBED(0x21),
    122         SERVICE_OPTION_OUT_OF_ORDER(0x22),
    123         NSAPI_IN_USE(0x23),
    124         ONLY_IPV4_ALLOWED(0x32),
    125         ONLY_IPV6_ALLOWED(0x33),
    126         ONLY_SINGLE_BEARER_ALLOWED(0x34),
    127         PROTOCOL_ERRORS(0x6F),
    128 
    129         // Local errors generated by Vendor RIL
    130         // specified in ril.h
    131         REGISTRATION_FAIL(-1),
    132         GPRS_REGISTRATION_FAIL(-2),
    133         SIGNAL_LOST(-3),
    134         PREF_RADIO_TECH_CHANGED(-4),
    135         RADIO_POWER_OFF(-5),
    136         TETHERED_CALL_ACTIVE(-6),
    137         ERROR_UNSPECIFIED(0xFFFF),
    138 
    139         // Errors generated by the Framework
    140         // specified here
    141         UNKNOWN(0x10000),
    142         RADIO_NOT_AVAILABLE(0x10001),
    143         UNACCEPTABLE_NETWORK_PARAMETER(0x10002),
    144         CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003);
    145 
    146         private final int mErrorCode;
    147         private static final HashMap<Integer, FailCause> sErrorCodeToFailCauseMap;
    148         static {
    149             sErrorCodeToFailCauseMap = new HashMap<Integer, FailCause>();
    150             for (FailCause fc : values()) {
    151                 sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
    152             }
    153         }
    154 
    155         FailCause(int errorCode) {
    156             mErrorCode = errorCode;
    157         }
    158 
    159         int getErrorCode() {
    160             return mErrorCode;
    161         }
    162 
    163         public boolean isPermanentFail() {
    164             return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
    165                    (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
    166                    (this == SERVICE_OPTION_NOT_SUPPORTED) ||
    167                    (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||
    168                    (this == PROTOCOL_ERRORS);
    169         }
    170 
    171         public boolean isEventLoggable() {
    172             return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
    173                     (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
    174                     (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
    175                     (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
    176                     (this == SERVICE_OPTION_NOT_SUPPORTED) ||
    177                     (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
    178                     (this == PROTOCOL_ERRORS) ||
    179                     (this == UNACCEPTABLE_NETWORK_PARAMETER);
    180         }
    181 
    182         public static FailCause fromInt(int errorCode) {
    183             FailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
    184             if (fc == null) {
    185                 fc = UNKNOWN;
    186             }
    187             return fc;
    188         }
    189     }
    190 
    191     public static class CallSetupException extends Exception {
    192         private int mRetryOverride = -1;
    193 
    194         CallSetupException (int retryOverride) {
    195             mRetryOverride = retryOverride;
    196         }
    197 
    198         public int getRetryOverride() {
    199             return mRetryOverride;
    200         }
    201     }
    202 
    203     // ***** Event codes for driving the state machine
    204     protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
    205     protected static final int EVENT_CONNECT = BASE + 0;
    206     protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
    207     protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
    208     protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
    209     protected static final int EVENT_DISCONNECT = BASE + 4;
    210     protected static final int EVENT_RIL_CONNECTED = BASE + 5;
    211     protected static final int EVENT_DISCONNECT_ALL = BASE + 6;
    212 
    213     private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL - BASE + 1;
    214     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    215     static {
    216         sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT";
    217         sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] =
    218                 "EVENT_SETUP_DATA_CONNECTION_DONE";
    219         sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE";
    220         sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE";
    221         sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT";
    222         sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED";
    223         sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL";
    224     }
    225     protected static String cmdToString(int cmd) {
    226         cmd -= BASE;
    227         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
    228             return sCmdToString[cmd];
    229         } else {
    230             return null;
    231         }
    232     }
    233 
    234     //***** Tag IDs for EventLog
    235     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
    236 
    237     //***** Member Variables
    238     protected ApnSetting mApn;
    239     protected int mTag;
    240     protected PhoneBase phone;
    241     protected int mRilVersion = -1;
    242     protected int cid;
    243     protected LinkProperties mLinkProperties = new LinkProperties();
    244     protected LinkCapabilities mCapabilities = new LinkCapabilities();
    245     protected long createTime;
    246     protected long lastFailTime;
    247     protected FailCause lastFailCause;
    248     protected int mRetryOverride = -1;
    249     protected static final String NULL_IP = "0.0.0.0";
    250     protected int mRefCount;
    251     Object userData;
    252 
    253     //***** Abstract methods
    254     @Override
    255     public abstract String toString();
    256 
    257     protected abstract void onConnect(ConnectionParams cp);
    258 
    259     protected abstract boolean isDnsOk(String[] domainNameServers);
    260 
    261     protected abstract void log(String s);
    262 
    263 
    264    //***** Constructor
    265     protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm,
    266             DataConnectionTracker dct) {
    267         super(name);
    268         setProcessedMessagesSize(100);
    269         if (DBG) log("DataConnection constructor E");
    270         this.phone = phone;
    271         this.mDataConnectionTracker = dct;
    272         mId = id;
    273         mRetryMgr = rm;
    274         this.cid = -1;
    275 
    276         setDbg(false);
    277         addState(mDefaultState);
    278             addState(mInactiveState, mDefaultState);
    279             addState(mActivatingState, mDefaultState);
    280             addState(mActiveState, mDefaultState);
    281             addState(mDisconnectingState, mDefaultState);
    282             addState(mDisconnectingErrorCreatingConnection, mDefaultState);
    283         setInitialState(mInactiveState);
    284 
    285         mApnList = new ArrayList<ApnContext>();
    286         if (DBG) log("DataConnection constructor X");
    287     }
    288 
    289     /**
    290      * TearDown the data connection.
    291      *
    292      * @param o will be returned in AsyncResult.userObj
    293      *          and is either a DisconnectParams or ConnectionParams.
    294      */
    295     private void tearDownData(Object o) {
    296         int discReason = RILConstants.DEACTIVATE_REASON_NONE;
    297         if ((o != null) && (o instanceof DisconnectParams)) {
    298             DisconnectParams dp = (DisconnectParams)o;
    299             Message m = dp.onCompletedMsg;
    300             if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
    301                 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
    302             } else if (TextUtils.equals(dp.reason, Phone.REASON_PDP_RESET)) {
    303                 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
    304             }
    305         }
    306         if (phone.mCM.getRadioState().isOn()) {
    307             if (DBG) log("tearDownData radio is on, call deactivateDataCall");
    308             phone.mCM.deactivateDataCall(cid, discReason, obtainMessage(EVENT_DEACTIVATE_DONE, o));
    309         } else {
    310             if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
    311             AsyncResult ar = new AsyncResult(o, null, null);
    312             sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar));
    313         }
    314     }
    315 
    316     /**
    317      * Send the connectionCompletedMsg.
    318      *
    319      * @param cp is the ConnectionParams
    320      * @param cause
    321      */
    322     private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
    323         Message connectionCompletedMsg = cp.onCompletedMsg;
    324         if (connectionCompletedMsg == null) {
    325             return;
    326         }
    327 
    328         long timeStamp = System.currentTimeMillis();
    329         connectionCompletedMsg.arg1 = cid;
    330 
    331         if (cause == FailCause.NONE) {
    332             createTime = timeStamp;
    333             AsyncResult.forMessage(connectionCompletedMsg);
    334         } else {
    335             lastFailCause = cause;
    336             lastFailTime = timeStamp;
    337             AsyncResult.forMessage(connectionCompletedMsg, cause,
    338                                    new CallSetupException(mRetryOverride));
    339         }
    340         if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause);
    341 
    342         connectionCompletedMsg.sendToTarget();
    343     }
    344 
    345     /**
    346      * Send ar.userObj if its a message, which is should be back to originator.
    347      *
    348      * @param dp is the DisconnectParams.
    349      */
    350     private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
    351         if (VDBG) log("NotifyDisconnectCompleted");
    352 
    353         ApnContext alreadySent = null;
    354         String reason = null;
    355 
    356         if (dp.onCompletedMsg != null) {
    357             // Get ApnContext, but only valid on GSM devices this is a string on CDMA devices.
    358             Message msg = dp.onCompletedMsg;
    359             if (msg.obj instanceof ApnContext) {
    360                 alreadySent = (ApnContext)msg.obj;
    361             }
    362             reason = dp.reason;
    363             if (VDBG) {
    364                 log(String.format("msg=%s msg.obj=%s", msg.toString(),
    365                     ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
    366             }
    367             AsyncResult.forMessage(msg);
    368             msg.sendToTarget();
    369         }
    370         if (sendAll) {
    371             for (ApnContext a : mApnList) {
    372                 if (a == alreadySent) continue;
    373                 if (reason != null) a.setReason(reason);
    374                 Message msg = mDataConnectionTracker.obtainMessage(
    375                         DataConnectionTracker.EVENT_DISCONNECT_DONE, a);
    376                 AsyncResult.forMessage(msg);
    377                 msg.sendToTarget();
    378             }
    379         }
    380 
    381         if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
    382     }
    383 
    384     protected int getRilRadioTechnology(int defaultRilRadioTechnology) {
    385         int rilRadioTechnology;
    386         if (mRilVersion < 6) {
    387             rilRadioTechnology = defaultRilRadioTechnology;
    388         } else {
    389             rilRadioTechnology = phone.getServiceState().getRilRadioTechnology() + 2;
    390         }
    391         return rilRadioTechnology;
    392     }
    393 
    394     /*
    395      * **************************************************************************
    396      * Begin Members and methods owned by DataConnectionTracker but stored
    397      * in a DataConnection because there is one per connection.
    398      * **************************************************************************
    399      */
    400 
    401     /*
    402      * The id is owned by DataConnectionTracker.
    403      */
    404     private int mId;
    405 
    406     /**
    407      * Get the DataConnection ID
    408      */
    409     public int getDataConnectionId() {
    410         return mId;
    411     }
    412 
    413     /*
    414      * The retry manager is currently owned by the DataConnectionTracker but is stored
    415      * in the DataConnection because there is one per connection. These methods
    416      * should only be used by the DataConnectionTracker although someday the retrying
    417      * maybe managed by the DataConnection itself and these methods could disappear.
    418      */
    419     private RetryManager mRetryMgr;
    420 
    421     /**
    422      * @return retry manager retryCount
    423      */
    424     public int getRetryCount() {
    425         return mRetryMgr.getRetryCount();
    426     }
    427 
    428     /**
    429      * @return retry manager retryTimer
    430      */
    431     public int getRetryTimer() {
    432         return mRetryMgr.getRetryTimer();
    433     }
    434 
    435     /**
    436      * increaseRetryCount of retry manager
    437      */
    438     public void increaseRetryCount() {
    439         mRetryMgr.increaseRetryCount();
    440     }
    441 
    442     /**
    443      * @return retry manager isRetryNeeded
    444      */
    445     public boolean isRetryNeeded() {
    446         return mRetryMgr.isRetryNeeded();
    447     }
    448 
    449     /**
    450      * resetRetryCount of retry manager
    451      */
    452     public void resetRetryCount() {
    453         mRetryMgr.resetRetryCount();
    454     }
    455 
    456     /**
    457      * set retryForeverUsingLasttimeout of retry manager
    458      */
    459     public void retryForeverUsingLastTimeout() {
    460         mRetryMgr.retryForeverUsingLastTimeout();
    461     }
    462 
    463     /**
    464      * @return retry manager isRetryForever
    465      */
    466     public boolean isRetryForever() {
    467         return mRetryMgr.isRetryForever();
    468     }
    469 
    470     /**
    471      * @return whether the retry config is set successfully or not
    472      */
    473     public boolean configureRetry(int maxRetryCount, int retryTime, int randomizationTime) {
    474         return mRetryMgr.configure(maxRetryCount, retryTime, randomizationTime);
    475     }
    476 
    477     /**
    478      * @return whether the retry config is set successfully or not
    479      */
    480     public boolean configureRetry(String configStr) {
    481         return mRetryMgr.configure(configStr);
    482     }
    483 
    484     /*
    485      * **************************************************************************
    486      * End members owned by DataConnectionTracker
    487      * **************************************************************************
    488      */
    489 
    490     /**
    491      * Clear all settings called when entering mInactiveState.
    492      */
    493     protected void clearSettings() {
    494         if (DBG) log("clearSettings");
    495 
    496         createTime = -1;
    497         lastFailTime = -1;
    498         lastFailCause = FailCause.NONE;
    499         mRetryOverride = -1;
    500         mRefCount = 0;
    501         cid = -1;
    502 
    503         mLinkProperties = new LinkProperties();
    504         mApn = null;
    505     }
    506 
    507     /**
    508      * Process setup completion.
    509      *
    510      * @param ar is the result
    511      * @return SetupResult.
    512      */
    513     private DataCallState.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
    514         DataCallState response = (DataCallState) ar.result;
    515         ConnectionParams cp = (ConnectionParams) ar.userObj;
    516         DataCallState.SetupResult result;
    517 
    518         if (ar.exception != null) {
    519             if (DBG) {
    520                 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
    521                     " response=" + response);
    522             }
    523 
    524             if (ar.exception instanceof CommandException
    525                     && ((CommandException) (ar.exception)).getCommandError()
    526                     == CommandException.Error.RADIO_NOT_AVAILABLE) {
    527                 result = DataCallState.SetupResult.ERR_BadCommand;
    528                 result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
    529             } else if ((response == null) || (response.version < 4)) {
    530                 result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;
    531             } else {
    532                 result = DataCallState.SetupResult.ERR_RilError;
    533                 result.mFailCause = FailCause.fromInt(response.status);
    534             }
    535         } else if (cp.tag != mTag) {
    536             if (DBG) {
    537                 log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
    538             }
    539             result = DataCallState.SetupResult.ERR_Stale;
    540         } else if (response.status != 0) {
    541             result = DataCallState.SetupResult.ERR_RilError;
    542             result.mFailCause = FailCause.fromInt(response.status);
    543         } else {
    544             if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
    545             cid = response.cid;
    546             result = updateLinkProperty(response).setupResult;
    547         }
    548 
    549         return result;
    550     }
    551 
    552     private int getSuggestedRetryTime(AsyncResult ar) {
    553         int retry = -1;
    554         if (ar.exception == null) {
    555             DataCallState response = (DataCallState) ar.result;
    556             retry =  response.suggestedRetryTime;
    557         }
    558         return retry;
    559     }
    560 
    561     private DataCallState.SetupResult setLinkProperties(DataCallState response,
    562             LinkProperties lp) {
    563         // Check if system property dns usable
    564         boolean okToUseSystemPropertyDns = false;
    565         String propertyPrefix = "net." + response.ifname + ".";
    566         String dnsServers[] = new String[2];
    567         dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
    568         dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
    569         okToUseSystemPropertyDns = isDnsOk(dnsServers);
    570 
    571         // set link properties based on data call response
    572         return response.setLinkProperties(lp, okToUseSystemPropertyDns);
    573     }
    574 
    575     public static class UpdateLinkPropertyResult {
    576         public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
    577         public LinkProperties oldLp;
    578         public LinkProperties newLp;
    579         public UpdateLinkPropertyResult(LinkProperties curLp) {
    580             oldLp = curLp;
    581             newLp = curLp;
    582         }
    583     }
    584 
    585     private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
    586         UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
    587 
    588         if (newState == null) return result;
    589 
    590         DataCallState.SetupResult setupResult;
    591         result.newLp = new LinkProperties();
    592 
    593         // set link properties based on data call response
    594         result.setupResult = setLinkProperties(newState, result.newLp);
    595         if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
    596             if (DBG) log("updateLinkProperty failed : " + result.setupResult);
    597             return result;
    598         }
    599         // copy HTTP proxy as it is not part DataCallState.
    600         result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
    601 
    602         if (DBG && (! result.oldLp.equals(result.newLp))) {
    603             log("updateLinkProperty old LP=" + result.oldLp);
    604             log("updateLinkProperty new LP=" + result.newLp);
    605         }
    606         mLinkProperties = result.newLp;
    607 
    608         return result;
    609     }
    610 
    611     /**
    612      * The parent state for all other states.
    613      */
    614     private class DcDefaultState extends State {
    615         @Override
    616         public void enter() {
    617             phone.mCM.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null);
    618         }
    619         @Override
    620         public void exit() {
    621             phone.mCM.unregisterForRilConnected(getHandler());
    622         }
    623         @Override
    624         public boolean processMessage(Message msg) {
    625             AsyncResult ar;
    626 
    627             switch (msg.what) {
    628                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
    629                     if (mAc != null) {
    630                         if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
    631                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    632                                 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
    633                     } else {
    634                         mAc = new AsyncChannel();
    635                         mAc.connected(null, getHandler(), msg.replyTo);
    636                         if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
    637                         mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
    638                                 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
    639                     }
    640                     break;
    641                 }
    642                 case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
    643                     if (VDBG) log("CMD_CHANNEL_DISCONNECT");
    644                     mAc.disconnect();
    645                     break;
    646                 }
    647                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    648                     if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
    649                     mAc = null;
    650                     break;
    651                 }
    652                 case DataConnectionAc.REQ_IS_INACTIVE: {
    653                     boolean val = getCurrentState() == mInactiveState;
    654                     if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
    655                     mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
    656                     break;
    657                 }
    658                 case DataConnectionAc.REQ_GET_CID: {
    659                     if (VDBG) log("REQ_GET_CID  cid=" + cid);
    660                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
    661                     break;
    662                 }
    663                 case DataConnectionAc.REQ_GET_APNSETTING: {
    664                     if (VDBG) log("REQ_GET_APNSETTING  apnSetting=" + mApn);
    665                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
    666                     break;
    667                 }
    668                 case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
    669                     LinkProperties lp = new LinkProperties(mLinkProperties);
    670                     if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
    671                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
    672                     break;
    673                 }
    674                 case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
    675                     ProxyProperties proxy = (ProxyProperties) msg.obj;
    676                     if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
    677                     mLinkProperties.setHttpProxy(proxy);
    678                     mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
    679                     break;
    680                 }
    681                 case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
    682                     DataCallState newState = (DataCallState) msg.obj;
    683                     UpdateLinkPropertyResult result =
    684                                              updateLinkProperty(newState);
    685                     if (VDBG) {
    686                         log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
    687                             + result + " newState=" + newState);
    688                     }
    689                     mAc.replyToMessage(msg,
    690                                    DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
    691                                    result);
    692                     break;
    693                 }
    694                 case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
    695                     LinkCapabilities lc = new LinkCapabilities(mCapabilities);
    696                     if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
    697                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
    698                     break;
    699                 }
    700                 case DataConnectionAc.REQ_RESET:
    701                     if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
    702                     mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
    703                     transitionTo(mInactiveState);
    704                     break;
    705                 case DataConnectionAc.REQ_GET_REFCOUNT: {
    706                     if (VDBG) log("REQ_GET_REFCOUNT  refCount=" + mRefCount);
    707                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount);
    708                     break;
    709                 }
    710                 case DataConnectionAc.REQ_ADD_APNCONTEXT: {
    711                     ApnContext apnContext = (ApnContext) msg.obj;
    712                     if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType());
    713                     if (!mApnList.contains(apnContext)) {
    714                         mApnList.add(apnContext);
    715                     }
    716                     mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT);
    717                     break;
    718                 }
    719                 case DataConnectionAc.REQ_REMOVE_APNCONTEXT: {
    720                     ApnContext apnContext = (ApnContext) msg.obj;
    721                     if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType());
    722                     mApnList.remove(apnContext);
    723                     mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT);
    724                     break;
    725                 }
    726                 case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
    727                     if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
    728                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
    729                                        new ArrayList<ApnContext>(mApnList));
    730                     break;
    731                 }
    732                 case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
    733                     PendingIntent intent = (PendingIntent) msg.obj;
    734                     if (VDBG) log("REQ_SET_RECONNECT_INTENT");
    735                     mReconnectIntent = intent;
    736                     mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT);
    737                     break;
    738                 }
    739                 case DataConnectionAc.REQ_GET_RECONNECT_INTENT: {
    740                     if (VDBG) log("REQ_GET_RECONNECT_INTENT");
    741                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT,
    742                                        mReconnectIntent);
    743                     break;
    744                 }
    745                 case EVENT_CONNECT:
    746                     if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
    747                     ConnectionParams cp = (ConnectionParams) msg.obj;
    748                     notifyConnectCompleted(cp, FailCause.UNKNOWN);
    749                     break;
    750 
    751                 case EVENT_DISCONNECT:
    752                     if (DBG) {
    753                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT" + mRefCount);
    754                     }
    755                     deferMessage(msg);
    756                     break;
    757 
    758                 case EVENT_DISCONNECT_ALL:
    759                     if (DBG) {
    760                         log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL" + mRefCount);
    761                     }
    762                     deferMessage(msg);
    763                     break;
    764 
    765                 case EVENT_RIL_CONNECTED:
    766                     ar = (AsyncResult)msg.obj;
    767                     if (ar.exception == null) {
    768                         mRilVersion = (Integer)ar.result;
    769                         if (DBG) {
    770                             log("DcDefaultState: msg.what=EVENT_RIL_CONNECTED mRilVersion=" +
    771                                 mRilVersion);
    772                         }
    773                     } else {
    774                         log("Unexpected exception on EVENT_RIL_CONNECTED");
    775                         mRilVersion = -1;
    776                     }
    777                     break;
    778 
    779                 default:
    780                     if (DBG) {
    781                         log("DcDefaultState: shouldn't happen but ignore msg.what=0x" +
    782                                 Integer.toHexString(msg.what));
    783                     }
    784                     break;
    785             }
    786 
    787             return HANDLED;
    788         }
    789     }
    790     private DcDefaultState mDefaultState = new DcDefaultState();
    791 
    792     /**
    793      * The state machine is inactive and expects a EVENT_CONNECT.
    794      */
    795     private class DcInactiveState extends State {
    796         private ConnectionParams mConnectionParams = null;
    797         private FailCause mFailCause = null;
    798         private DisconnectParams mDisconnectParams = null;
    799 
    800         public void setEnterNotificationParams(ConnectionParams cp, FailCause cause,
    801                                                int retryOverride) {
    802             if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
    803             mConnectionParams = cp;
    804             mFailCause = cause;
    805             mRetryOverride = retryOverride;
    806         }
    807 
    808         public void setEnterNotificationParams(DisconnectParams dp) {
    809             if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
    810             mDisconnectParams = dp;
    811         }
    812 
    813         @Override
    814         public void enter() {
    815             mTag += 1;
    816 
    817             /**
    818              * Now that we've transitioned to Inactive state we
    819              * can send notifications. Previously we sent the
    820              * notifications in the processMessage handler but
    821              * that caused a race condition because the synchronous
    822              * call to isInactive.
    823              */
    824             if ((mConnectionParams != null) && (mFailCause != null)) {
    825                 if (VDBG) log("DcInactiveState: enter notifyConnectCompleted");
    826                 notifyConnectCompleted(mConnectionParams, mFailCause);
    827             }
    828             if (mDisconnectParams != null) {
    829                 if (VDBG) log("DcInactiveState: enter notifyDisconnectCompleted");
    830                 notifyDisconnectCompleted(mDisconnectParams, true);
    831             }
    832             clearSettings();
    833         }
    834 
    835         @Override
    836         public void exit() {
    837             // clear notifications
    838             mConnectionParams = null;
    839             mFailCause = null;
    840             mDisconnectParams = null;
    841         }
    842 
    843         @Override
    844         public boolean processMessage(Message msg) {
    845             boolean retVal;
    846 
    847             switch (msg.what) {
    848                 case DataConnectionAc.REQ_RESET:
    849                     if (DBG) {
    850                         log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
    851                     }
    852                     mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
    853                     retVal = HANDLED;
    854                     break;
    855 
    856                 case EVENT_CONNECT:
    857                     ConnectionParams cp = (ConnectionParams) msg.obj;
    858                     cp.tag = mTag;
    859                     if (DBG) {
    860                         log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = "
    861                                 + mRefCount);
    862                     }
    863                     mRefCount = 1;
    864                     onConnect(cp);
    865                     transitionTo(mActivatingState);
    866                     retVal = HANDLED;
    867                     break;
    868 
    869                 case EVENT_DISCONNECT:
    870                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
    871                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
    872                     retVal = HANDLED;
    873                     break;
    874 
    875                 case EVENT_DISCONNECT_ALL:
    876                     if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
    877                     notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
    878                     retVal = HANDLED;
    879                     break;
    880 
    881                 default:
    882                     if (VDBG) {
    883                         log("DcInactiveState nothandled msg.what=0x" +
    884                                 Integer.toHexString(msg.what));
    885                     }
    886                     retVal = NOT_HANDLED;
    887                     break;
    888             }
    889             return retVal;
    890         }
    891     }
    892     private DcInactiveState mInactiveState = new DcInactiveState();
    893 
    894     /**
    895      * The state machine is activating a connection.
    896      */
    897     private class DcActivatingState extends State {
    898         @Override
    899         public boolean processMessage(Message msg) {
    900             boolean retVal;
    901             AsyncResult ar;
    902             ConnectionParams cp;
    903 
    904             switch (msg.what) {
    905                 case EVENT_CONNECT:
    906                     if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "
    907                             + mRefCount);
    908                     deferMessage(msg);
    909                     retVal = HANDLED;
    910                     break;
    911 
    912                 case EVENT_SETUP_DATA_CONNECTION_DONE:
    913                     if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
    914 
    915                     ar = (AsyncResult) msg.obj;
    916                     cp = (ConnectionParams) ar.userObj;
    917 
    918                     DataCallState.SetupResult result = onSetupConnectionCompleted(ar);
    919                     if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);
    920                     switch (result) {
    921                         case SUCCESS:
    922                             // All is well
    923                             mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
    924                             transitionTo(mActiveState);
    925                             break;
    926                         case ERR_BadCommand:
    927                             // Vendor ril rejected the command and didn't connect.
    928                             // Transition to inactive but send notifications after
    929                             // we've entered the mInactive state.
    930                             mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);
    931                             transitionTo(mInactiveState);
    932                             break;
    933                         case ERR_UnacceptableParameter:
    934                             // The addresses given from the RIL are bad
    935                             tearDownData(cp);
    936                             transitionTo(mDisconnectingErrorCreatingConnection);
    937                             break;
    938                         case ERR_GetLastErrorFromRil:
    939                             // Request failed and this is an old RIL
    940                             phone.mCM.getLastDataCallFailCause(
    941                                     obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
    942                             break;
    943                         case ERR_RilError:
    944                             // Request failed and mFailCause has the reason
    945                             mInactiveState.setEnterNotificationParams(cp, result.mFailCause,
    946                                                                       getSuggestedRetryTime(ar));
    947                             transitionTo(mInactiveState);
    948                             break;
    949                         case ERR_Stale:
    950                             // Request is stale, ignore.
    951                             break;
    952                         default:
    953                             throw new RuntimeException("Unknown SetupResult, should not happen");
    954                     }
    955                     retVal = HANDLED;
    956                     break;
    957 
    958                 case EVENT_GET_LAST_FAIL_DONE:
    959                     ar = (AsyncResult) msg.obj;
    960                     cp = (ConnectionParams) ar.userObj;
    961                     FailCause cause = FailCause.UNKNOWN;
    962 
    963                     if (cp.tag == mTag) {
    964                         if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");
    965                         if (ar.exception == null) {
    966                             int rilFailCause = ((int[]) (ar.result))[0];
    967                             cause = FailCause.fromInt(rilFailCause);
    968                         }
    969                         // Transition to inactive but send notifications after
    970                         // we've entered the mInactive state.
    971                         mInactiveState.setEnterNotificationParams(cp, cause, -1);
    972                         transitionTo(mInactiveState);
    973                     } else {
    974                         if (DBG) {
    975                             log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
    976                                 + cp.tag + ", mTag=" + mTag);
    977                         }
    978                     }
    979 
    980                     retVal = HANDLED;
    981                     break;
    982 
    983                 default:
    984                     if (VDBG) {
    985                         log("DcActivatingState not handled msg.what=0x" +
    986                                 Integer.toHexString(msg.what));
    987                     }
    988                     retVal = NOT_HANDLED;
    989                     break;
    990             }
    991             return retVal;
    992         }
    993     }
    994     private DcActivatingState mActivatingState = new DcActivatingState();
    995 
    996     /**
    997      * The state machine is connected, expecting an EVENT_DISCONNECT.
    998      */
    999     private class DcActiveState extends State {
   1000         private ConnectionParams mConnectionParams = null;
   1001         private FailCause mFailCause = null;
   1002 
   1003         public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
   1004             if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
   1005             mConnectionParams = cp;
   1006             mFailCause = cause;
   1007         }
   1008 
   1009         @Override public void enter() {
   1010             /**
   1011              * Now that we've transitioned to Active state we
   1012              * can send notifications. Previously we sent the
   1013              * notifications in the processMessage handler but
   1014              * that caused a race condition because the synchronous
   1015              * call to isActive.
   1016              */
   1017             if ((mConnectionParams != null) && (mFailCause != null)) {
   1018                 if (VDBG) log("DcActiveState: enter notifyConnectCompleted");
   1019                 notifyConnectCompleted(mConnectionParams, mFailCause);
   1020             }
   1021         }
   1022 
   1023         @Override
   1024         public void exit() {
   1025             // clear notifications
   1026             mConnectionParams = null;
   1027             mFailCause = null;
   1028         }
   1029 
   1030         @Override
   1031         public boolean processMessage(Message msg) {
   1032             boolean retVal;
   1033 
   1034             switch (msg.what) {
   1035                 case EVENT_CONNECT:
   1036                     mRefCount++;
   1037                     if (DBG) log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mRefCount);
   1038                     if (msg.obj != null) {
   1039                         notifyConnectCompleted((ConnectionParams) msg.obj, FailCause.NONE);
   1040                     }
   1041                     retVal = HANDLED;
   1042                     break;
   1043                 case EVENT_DISCONNECT:
   1044                     mRefCount--;
   1045                     if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + mRefCount);
   1046                     if (mRefCount == 0)
   1047                     {
   1048                         DisconnectParams dp = (DisconnectParams) msg.obj;
   1049                         dp.tag = mTag;
   1050                         tearDownData(dp);
   1051                         transitionTo(mDisconnectingState);
   1052                     } else {
   1053                         if (msg.obj != null) {
   1054                             notifyDisconnectCompleted((DisconnectParams) msg.obj, false);
   1055                         }
   1056                     }
   1057                     retVal = HANDLED;
   1058                     break;
   1059 
   1060                 case EVENT_DISCONNECT_ALL:
   1061                     if (DBG) {
   1062                         log("DcActiveState msg.what=EVENT_DISCONNECT_ALL RefCount=" + mRefCount);
   1063                     }
   1064                     mRefCount = 0;
   1065                     DisconnectParams dp = (DisconnectParams) msg.obj;
   1066                     dp.tag = mTag;
   1067                     tearDownData(dp);
   1068                     transitionTo(mDisconnectingState);
   1069                     retVal = HANDLED;
   1070                     break;
   1071 
   1072                 default:
   1073                     if (VDBG) {
   1074                         log("DcActiveState not handled msg.what=0x" +
   1075                                 Integer.toHexString(msg.what));
   1076                     }
   1077                     retVal = NOT_HANDLED;
   1078                     break;
   1079             }
   1080             return retVal;
   1081         }
   1082     }
   1083     private DcActiveState mActiveState = new DcActiveState();
   1084 
   1085     /**
   1086      * The state machine is disconnecting.
   1087      */
   1088     private class DcDisconnectingState extends State {
   1089         @Override
   1090         public boolean processMessage(Message msg) {
   1091             boolean retVal;
   1092 
   1093             switch (msg.what) {
   1094                 case EVENT_CONNECT:
   1095                     if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
   1096                             + mRefCount);
   1097                     deferMessage(msg);
   1098                     retVal = HANDLED;
   1099                     break;
   1100 
   1101                 case EVENT_DEACTIVATE_DONE:
   1102                     if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
   1103                     AsyncResult ar = (AsyncResult) msg.obj;
   1104                     DisconnectParams dp = (DisconnectParams) ar.userObj;
   1105                     if (dp.tag == mTag) {
   1106                         // Transition to inactive but send notifications after
   1107                         // we've entered the mInactive state.
   1108                         mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
   1109                         transitionTo(mInactiveState);
   1110                     } else {
   1111                         if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
   1112                                 + dp.tag + " mTag=" + mTag);
   1113                     }
   1114                     retVal = HANDLED;
   1115                     break;
   1116 
   1117                 default:
   1118                     if (VDBG) {
   1119                         log("DcDisconnectingState not handled msg.what=0x" +
   1120                                 Integer.toHexString(msg.what));
   1121                     }
   1122                     retVal = NOT_HANDLED;
   1123                     break;
   1124             }
   1125             return retVal;
   1126         }
   1127     }
   1128     private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
   1129 
   1130     /**
   1131      * The state machine is disconnecting after an creating a connection.
   1132      */
   1133     private class DcDisconnectionErrorCreatingConnection extends State {
   1134         @Override
   1135         public boolean processMessage(Message msg) {
   1136             boolean retVal;
   1137 
   1138             switch (msg.what) {
   1139                 case EVENT_DEACTIVATE_DONE:
   1140                     AsyncResult ar = (AsyncResult) msg.obj;
   1141                     ConnectionParams cp = (ConnectionParams) ar.userObj;
   1142                     if (cp.tag == mTag) {
   1143                         if (DBG) {
   1144                             log("DcDisconnectionErrorCreatingConnection" +
   1145                                 " msg.what=EVENT_DEACTIVATE_DONE");
   1146                         }
   1147 
   1148                         // Transition to inactive but send notifications after
   1149                         // we've entered the mInactive state.
   1150                         mInactiveState.setEnterNotificationParams(cp,
   1151                                 FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1);
   1152                         transitionTo(mInactiveState);
   1153                     } else {
   1154                         if (DBG) {
   1155                             log("DcDisconnectionErrorCreatingConnection EVENT_DEACTIVATE_DONE" +
   1156                                     " stale dp.tag=" + cp.tag + ", mTag=" + mTag);
   1157                         }
   1158                     }
   1159                     retVal = HANDLED;
   1160                     break;
   1161 
   1162                 default:
   1163                     if (VDBG) {
   1164                         log("DcDisconnectionErrorCreatingConnection not handled msg.what=0x"
   1165                                 + Integer.toHexString(msg.what));
   1166                     }
   1167                     retVal = NOT_HANDLED;
   1168                     break;
   1169             }
   1170             return retVal;
   1171         }
   1172     }
   1173     private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
   1174                 new DcDisconnectionErrorCreatingConnection();
   1175 
   1176     // ******* public interface
   1177 
   1178     /**
   1179      * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
   1180      * Used for cellular networks that use Acesss Point Names (APN) such
   1181      * as GSM networks.
   1182      *
   1183      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
   1184      *        With AsyncResult.userObj set to the original msg.obj,
   1185      *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
   1186      * @param apn is the Access Point Name to bring up a connection to
   1187      */
   1188     public void bringUp(Message onCompletedMsg, ApnSetting apn) {
   1189         sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
   1190     }
   1191 
   1192     /**
   1193      * Tear down the connection through the apn on the network.
   1194      *
   1195      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
   1196      *        With AsyncResult.userObj set to the original msg.obj.
   1197      */
   1198     public void tearDown(String reason, Message onCompletedMsg) {
   1199         sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
   1200     }
   1201 
   1202     /**
   1203      * Tear down the connection through the apn on the network.  Ignores refcount and
   1204      * and always tears down.
   1205      *
   1206      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
   1207      *        With AsyncResult.userObj set to the original msg.obj.
   1208      */
   1209     public void tearDownAll(String reason, Message onCompletedMsg) {
   1210         sendMessage(obtainMessage(EVENT_DISCONNECT_ALL,
   1211                 new DisconnectParams(reason, onCompletedMsg)));
   1212     }
   1213 
   1214     /**
   1215      * @return the string for msg.what as our info.
   1216      */
   1217     @Override
   1218     protected String getMessageInfo(Message msg) {
   1219         String info = null;
   1220         info = cmdToString(msg.what);
   1221         if (info == null) {
   1222             info = DataConnectionAc.cmdToString(msg.what);
   1223         }
   1224         return info;
   1225     }
   1226 
   1227     /**
   1228      * Dump the current state.
   1229      *
   1230      * @param fd
   1231      * @param pw
   1232      * @param args
   1233      */
   1234     @Override
   1235     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1236         pw.print("DataConnection ");
   1237         super.dump(fd, pw, args);
   1238         pw.println(" mApnList=" + mApnList);
   1239         pw.flush();
   1240         pw.println(" mDataConnectionTracker=" + mDataConnectionTracker);
   1241         pw.println(" mApn=" + mApn);
   1242         pw.println(" mTag=" + mTag);
   1243         pw.flush();
   1244         pw.println(" phone=" + phone);
   1245         pw.println(" mRilVersion=" + mRilVersion);
   1246         pw.println(" cid=" + cid);
   1247         pw.flush();
   1248         pw.println(" mLinkProperties=" + mLinkProperties);
   1249         pw.flush();
   1250         pw.println(" mCapabilities=" + mCapabilities);
   1251         pw.println(" createTime=" + TimeUtils.logTimeOfDay(createTime));
   1252         pw.println(" lastFailTime=" + TimeUtils.logTimeOfDay(lastFailTime));
   1253         pw.println(" lastFailCause=" + lastFailCause);
   1254         pw.flush();
   1255         pw.println(" mRetryOverride=" + mRetryOverride);
   1256         pw.println(" mRefCount=" + mRefCount);
   1257         pw.println(" userData=" + userData);
   1258         if (mRetryMgr != null) pw.println(" " + mRetryMgr);
   1259         pw.flush();
   1260     }
   1261 }
   1262