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