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