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