[go: nahoru, domu]

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