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