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