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