DataConnection.java revision 4c31e4c0d2db31fe84081aa6f1e2bcc08b31f9d3
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.CarrierSignalAgent;
21import com.android.internal.telephony.CommandException;
22import com.android.internal.telephony.DctConstants;
23import com.android.internal.telephony.Phone;
24import com.android.internal.telephony.PhoneConstants;
25import com.android.internal.telephony.RILConstants;
26import com.android.internal.telephony.RetryManager;
27import com.android.internal.telephony.ServiceStateTracker;
28import com.android.internal.util.AsyncChannel;
29import com.android.internal.util.Protocol;
30import com.android.internal.util.State;
31import com.android.internal.util.StateMachine;
32
33import android.app.PendingIntent;
34import android.content.Context;
35import android.net.ConnectivityManager;
36import android.net.LinkProperties;
37import android.net.NetworkAgent;
38import android.net.NetworkCapabilities;
39import android.net.NetworkInfo;
40import android.net.NetworkMisc;
41import android.net.ProxyInfo;
42import android.os.AsyncResult;
43import android.os.Looper;
44import android.os.Message;
45import android.os.SystemClock;
46import android.os.SystemProperties;
47import android.telephony.Rlog;
48import android.telephony.ServiceState;
49import android.telephony.TelephonyManager;
50import android.text.TextUtils;
51import android.util.Pair;
52import android.util.Patterns;
53import android.util.TimeUtils;
54
55import java.io.FileDescriptor;
56import java.io.PrintWriter;
57import java.io.StringWriter;
58import java.util.ArrayList;
59import java.util.Locale;
60import java.util.concurrent.atomic.AtomicInteger;
61import java.net.InetAddress;
62import java.util.Collection;
63import java.util.HashMap;
64
65/**
66 * {@hide}
67 *
68 * DataConnection StateMachine.
69 *
70 * This a class for representing a single data connection, with instances of this
71 * class representing a connection via the cellular network. There may be multiple
72 * data connections and all of them are managed by the <code>DataConnectionTracker</code>.
73 *
74 * NOTE: All DataConnection objects must be running on the same looper, which is the default
75 * as the coordinator has members which are used without synchronization.
76 */
77public class DataConnection extends StateMachine {
78    private static final boolean DBG = true;
79    private static final boolean VDBG = true;
80
81    private static final String NETWORK_TYPE = "MOBILE";
82
83    // The data connection controller
84    private DcController mDcController;
85
86    // The Tester for failing all bringup's
87    private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
88
89    private static AtomicInteger mInstanceNumber = new AtomicInteger(0);
90    private AsyncChannel mAc;
91
92    // The DCT that's talking to us, we only support one!
93    private DcTracker mDct = null;
94
95    protected String[] mPcscfAddr;
96
97    /**
98     * Used internally for saving connecting parameters.
99     */
100    public static class ConnectionParams {
101        int mTag;
102        ApnContext mApnContext;
103        int mProfileId;
104        int mRilRat;
105        Message mOnCompletedMsg;
106        final int mConnectionGeneration;
107
108        ConnectionParams(ApnContext apnContext, int profileId,
109                int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) {
110            mApnContext = apnContext;
111            mProfileId = profileId;
112            mRilRat = rilRadioTechnology;
113            mOnCompletedMsg = onCompletedMsg;
114            mConnectionGeneration = connectionGeneration;
115        }
116
117        @Override
118        public String toString() {
119            return "{mTag=" + mTag + " mApnContext=" + mApnContext
120                    + " mProfileId=" + mProfileId
121                    + " mRat=" + mRilRat
122                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
123        }
124    }
125
126    /**
127     * Used internally for saving disconnecting parameters.
128     */
129    public static class DisconnectParams {
130        int mTag;
131        public ApnContext mApnContext;
132        String mReason;
133        Message mOnCompletedMsg;
134
135        DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
136            mApnContext = apnContext;
137            mReason = reason;
138            mOnCompletedMsg = onCompletedMsg;
139        }
140
141        @Override
142        public String toString() {
143            return "{mTag=" + mTag + " mApnContext=" + mApnContext
144                    + " mReason=" + mReason
145                    + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
146        }
147    }
148
149    private ApnSetting mApnSetting;
150    private ConnectionParams mConnectionParams;
151    private DisconnectParams mDisconnectParams;
152    private DcFailCause mDcFailCause;
153
154    private Phone mPhone;
155    private LinkProperties mLinkProperties = new LinkProperties();
156    private long mCreateTime;
157    private long mLastFailTime;
158    private DcFailCause mLastFailCause;
159    private static final String NULL_IP = "0.0.0.0";
160    private Object mUserData;
161    private int mRilRat = Integer.MAX_VALUE;
162    private int mDataRegState = Integer.MAX_VALUE;
163    private NetworkInfo mNetworkInfo;
164    private NetworkAgent mNetworkAgent;
165
166    int mTag;
167    public int mCid;
168    public 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    public 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    public 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    public 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                cp.mRilRat,
488                cp.mProfileId,
489                mApnSetting.apn, mApnSetting.user, mApnSetting.password,
490                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            alreadySent = cp.mApnContext;
572
573            long timeStamp = System.currentTimeMillis();
574            connectionCompletedMsg.arg1 = mCid;
575
576            if (cause == DcFailCause.NONE) {
577                mCreateTime = timeStamp;
578                AsyncResult.forMessage(connectionCompletedMsg);
579            } else {
580                mLastFailCause = cause;
581                mLastFailTime = timeStamp;
582
583                // Return message with a Throwable exception to signify an error.
584                if (cause == null) cause = DcFailCause.UNKNOWN;
585                AsyncResult.forMessage(connectionCompletedMsg, cause,
586                        new Throwable(cause.toString()));
587            }
588            if (DBG) {
589                log("notifyConnectCompleted at " + timeStamp + " cause=" + cause
590                        + " connectionCompletedMsg=" + msgToString(connectionCompletedMsg));
591            }
592
593            connectionCompletedMsg.sendToTarget();
594        }
595        if (sendAll) {
596            log("Send to all. " + alreadySent + " " + cause.toString());
597            notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR,
598                    cause.toString());
599        }
600    }
601
602    /**
603     * Send ar.userObj if its a message, which is should be back to originator.
604     *
605     * @param dp is the DisconnectParams.
606     */
607    private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) {
608        if (VDBG) log("NotifyDisconnectCompleted");
609
610        ApnContext alreadySent = null;
611        String reason = null;
612
613        if (dp != null && dp.mOnCompletedMsg != null) {
614            // Get the completed message but only use it once
615            Message msg = dp.mOnCompletedMsg;
616            dp.mOnCompletedMsg = null;
617            if (msg.obj instanceof ApnContext) {
618                alreadySent = (ApnContext)msg.obj;
619            }
620            reason = dp.mReason;
621            if (VDBG) {
622                log(String.format("msg=%s msg.obj=%s", msg.toString(),
623                    ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
624            }
625            AsyncResult.forMessage(msg);
626            msg.sendToTarget();
627        }
628        if (sendAll) {
629            if (reason == null) {
630                reason = DcFailCause.UNKNOWN.toString();
631            }
632            notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason);
633        }
634        if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
635    }
636
637    /*
638     * **************************************************************************
639     * Begin Members and methods owned by DataConnectionTracker but stored
640     * in a DataConnection because there is one per connection.
641     * **************************************************************************
642     */
643
644    /*
645     * The id is owned by DataConnectionTracker.
646     */
647    private int mId;
648
649    /**
650     * Get the DataConnection ID
651     */
652    public int getDataConnectionId() {
653        return mId;
654    }
655
656    /*
657     * **************************************************************************
658     * End members owned by DataConnectionTracker
659     * **************************************************************************
660     */
661
662    /**
663     * Clear all settings called when entering mInactiveState.
664     */
665    private void clearSettings() {
666        if (DBG) log("clearSettings");
667
668        mCreateTime = -1;
669        mLastFailTime = -1;
670        mLastFailCause = DcFailCause.NONE;
671        mCid = -1;
672
673        mPcscfAddr = new String[5];
674
675        mLinkProperties = new LinkProperties();
676        mApnContexts.clear();
677        mApnSetting = null;
678        mDcFailCause = null;
679    }
680
681    /**
682     * Process setup completion.
683     *
684     * @param ar is the result
685     * @return SetupResult.
686     */
687    private DataCallResponse.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
688        DataCallResponse response = (DataCallResponse) ar.result;
689        ConnectionParams cp = (ConnectionParams) ar.userObj;
690        DataCallResponse.SetupResult result;
691
692        if (cp.mTag != mTag) {
693            if (DBG) {
694                log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag);
695            }
696            result = DataCallResponse.SetupResult.ERR_Stale;
697        } else if (ar.exception != null) {
698            if (DBG) {
699                log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
700                    " response=" + response);
701            }
702
703            if (ar.exception instanceof CommandException
704                    && ((CommandException) (ar.exception)).getCommandError()
705                    == CommandException.Error.RADIO_NOT_AVAILABLE) {
706                result = DataCallResponse.SetupResult.ERR_BadCommand;
707                result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
708            } else if ((response == null) || (response.version < 4)) {
709                result = DataCallResponse.SetupResult.ERR_GetLastErrorFromRil;
710            } else {
711                result = DataCallResponse.SetupResult.ERR_RilError;
712                result.mFailCause = DcFailCause.fromInt(response.status);
713            }
714        } else if (response.status != 0) {
715            result = DataCallResponse.SetupResult.ERR_RilError;
716            result.mFailCause = DcFailCause.fromInt(response.status);
717        } else {
718            if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
719            mCid = response.cid;
720
721            mPcscfAddr = response.pcscf;
722
723            result = updateLinkProperty(response).setupResult;
724        }
725
726        return result;
727    }
728
729    private boolean isDnsOk(String[] domainNameServers) {
730        if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
731                && !mPhone.isDnsCheckDisabled()) {
732            // Work around a race condition where QMI does not fill in DNS:
733            // Deactivate PDP and let DataConnectionTracker retry.
734            // Do not apply the race condition workaround for MMS APN
735            // if Proxy is an IP-address.
736            // Otherwise, the default APN will not be restored anymore.
737            if (!mApnSetting.types[0].equals(PhoneConstants.APN_TYPE_MMS)
738                || !isIpAddress(mApnSetting.mmsProxy)) {
739                log(String.format(
740                        "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s",
741                        mApnSetting.types[0], PhoneConstants.APN_TYPE_MMS, mApnSetting.mmsProxy,
742                        isIpAddress(mApnSetting.mmsProxy)));
743                return false;
744            }
745        }
746        return true;
747    }
748
749    private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000";
750    private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800";
751    private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576";
752    private static final String TCP_BUFFER_SIZES_1XRTT= "16384,32768,131072,4096,16384,102400";
753    private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144";
754    private static final String TCP_BUFFER_SIZES_EHRPD= "131072,262144,1048576,4096,16384,524288";
755    private static final String TCP_BUFFER_SIZES_HSDPA= "61167,367002,1101005,8738,52429,262114";
756    private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990";
757    private static final String TCP_BUFFER_SIZES_LTE  =
758            "524288,1048576,2097152,262144,524288,1048576";
759    private static final String TCP_BUFFER_SIZES_HSPAP= "122334,734003,2202010,32040,192239,576717";
760
761    private void updateTcpBufferSizes(int rilRat) {
762        String sizes = null;
763        String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT);
764        // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex)
765        // - patch it up:
766        if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 ||
767                rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A ||
768                rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) {
769            ratName = "evdo";
770        }
771
772        // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
773        String[] configOverride = mPhone.getContext().getResources().getStringArray(
774                com.android.internal.R.array.config_mobile_tcp_buffers);
775        for (int i = 0; i < configOverride.length; i++) {
776            String[] split = configOverride[i].split(":");
777            if (ratName.equals(split[0]) && split.length == 2) {
778                sizes = split[1];
779                break;
780            }
781        }
782
783        if (sizes == null) {
784            // no override - use telephony defaults
785            // doing it this way allows device or carrier to just override the types they
786            // care about and inherit the defaults for the others.
787            switch (rilRat) {
788                case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS:
789                    sizes = TCP_BUFFER_SIZES_GPRS;
790                    break;
791                case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE:
792                    sizes = TCP_BUFFER_SIZES_EDGE;
793                    break;
794                case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS:
795                    sizes = TCP_BUFFER_SIZES_UMTS;
796                    break;
797                case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT:
798                    sizes = TCP_BUFFER_SIZES_1XRTT;
799                    break;
800                case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0:
801                case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A:
802                case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B:
803                    sizes = TCP_BUFFER_SIZES_EVDO;
804                    break;
805                case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD:
806                    sizes = TCP_BUFFER_SIZES_EHRPD;
807                    break;
808                case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA:
809                    sizes = TCP_BUFFER_SIZES_HSDPA;
810                    break;
811                case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA:
812                case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA:
813                    sizes = TCP_BUFFER_SIZES_HSPA;
814                    break;
815                case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
816                    sizes = TCP_BUFFER_SIZES_LTE;
817                    break;
818                case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
819                    sizes = TCP_BUFFER_SIZES_HSPAP;
820                    break;
821                default:
822                    // Leave empty - this will let ConnectivityService use the system default.
823                    break;
824            }
825        }
826        mLinkProperties.setTcpBufferSizes(sizes);
827    }
828
829    private NetworkCapabilities makeNetworkCapabilities() {
830        NetworkCapabilities result = new NetworkCapabilities();
831        result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
832
833        if (mApnSetting != null) {
834            for (String type : mApnSetting.types) {
835                switch (type) {
836                    case PhoneConstants.APN_TYPE_ALL: {
837                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
838                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
839                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
840                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
841                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
842                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
843                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
844                        break;
845                    }
846                    case PhoneConstants.APN_TYPE_DEFAULT: {
847                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
848                        break;
849                    }
850                    case PhoneConstants.APN_TYPE_MMS: {
851                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
852                        break;
853                    }
854                    case PhoneConstants.APN_TYPE_SUPL: {
855                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
856                        break;
857                    }
858                    case PhoneConstants.APN_TYPE_DUN: {
859                        ApnSetting securedDunApn = mDct.fetchDunApn();
860                        if (securedDunApn == null || securedDunApn.equals(mApnSetting)) {
861                            result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
862                        }
863                        break;
864                    }
865                    case PhoneConstants.APN_TYPE_FOTA: {
866                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
867                        break;
868                    }
869                    case PhoneConstants.APN_TYPE_IMS: {
870                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
871                        break;
872                    }
873                    case PhoneConstants.APN_TYPE_CBS: {
874                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
875                        break;
876                    }
877                    case PhoneConstants.APN_TYPE_IA: {
878                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
879                        break;
880                    }
881                    case PhoneConstants.APN_TYPE_EMERGENCY: {
882                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
883                        break;
884                    }
885                    default:
886                }
887            }
888
889            // If none of the APN types associated with this APN setting is metered,
890            // then we apply NOT_METERED capability to the network.
891            if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
892                    mPhone.getServiceState().getDataRoaming())) {
893                result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
894            }
895
896            result.maybeMarkCapabilitiesRestricted();
897        }
898        int up = 14;
899        int down = 14;
900        switch (mRilRat) {
901            case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: up = 80; down = 80; break;
902            case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: up = 59; down = 236; break;
903            case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: up = 384; down = 384; break;
904            case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A: // fall through
905            case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B: up = 14; down = 14; break;
906            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: up = 153; down = 2457; break;
907            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: up = 1843; down = 3174; break;
908            case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: up = 100; down = 100; break;
909            case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: up = 2048; down = 14336; break;
910            case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: up = 5898; down = 14336; break;
911            case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: up = 5898; down = 14336; break;
912            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: up = 1843; down = 5017; break;
913            case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: up = 51200; down = 102400; break;
914            case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: up = 153; down = 2516; break;
915            case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: up = 11264; down = 43008; break;
916            default:
917        }
918        result.setLinkUpstreamBandwidthKbps(up);
919        result.setLinkDownstreamBandwidthKbps(down);
920
921        result.setNetworkSpecifier(Integer.toString(mPhone.getSubId()));
922
923        return result;
924    }
925
926    private boolean isIpAddress(String address) {
927        if (address == null) return false;
928
929        return Patterns.IP_ADDRESS.matcher(address).matches();
930    }
931
932    private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response,
933            LinkProperties lp) {
934        // Check if system property dns usable
935        boolean okToUseSystemPropertyDns = false;
936        String propertyPrefix = "net." + response.ifname + ".";
937        String dnsServers[] = new String[2];
938        dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
939        dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
940        okToUseSystemPropertyDns = isDnsOk(dnsServers);
941
942        // set link properties based on data call response
943        return response.setLinkProperties(lp, okToUseSystemPropertyDns);
944    }
945
946    /**
947     * Initialize connection, this will fail if the
948     * apnSettings are not compatible.
949     *
950     * @param cp the Connection parameters
951     * @return true if initialization was successful.
952     */
953    private boolean initConnection(ConnectionParams cp) {
954        ApnContext apnContext = cp.mApnContext;
955        if (mApnSetting == null) {
956            // Only change apn setting if it isn't set, it will
957            // only NOT be set only if we're in DcInactiveState.
958            mApnSetting = apnContext.getApnSetting();
959        }
960        if (mApnSetting == null || !mApnSetting.canHandleType(apnContext.getApnType())) {
961            if (DBG) {
962                log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp
963                        + " dc=" + DataConnection.this);
964            }
965            return false;
966        }
967        mTag += 1;
968        mConnectionParams = cp;
969        mConnectionParams.mTag = mTag;
970
971        // always update the ConnectionParams with the latest or the
972        // connectionGeneration gets stale
973        mApnContexts.put(apnContext, cp);
974
975        if (DBG) {
976            log("initConnection: "
977                    + " RefCount=" + mApnContexts.size()
978                    + " mApnList=" + mApnContexts
979                    + " mConnectionParams=" + mConnectionParams);
980        }
981        return true;
982    }
983
984    /**
985     * The parent state for all other states.
986     */
987    private class DcDefaultState extends State {
988        @Override
989        public void enter() {
990            if (DBG) log("DcDefaultState: enter");
991
992            // Register for DRS or RAT change
993            mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),
994                    DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);
995
996            mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(),
997                    DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null);
998            mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(),
999                    DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null);
1000
1001            // Add ourselves to the list of data connections
1002            mDcController.addDc(DataConnection.this);
1003        }
1004        @Override
1005        public void exit() {
1006            if (DBG) log("DcDefaultState: exit");
1007
1008            // Unregister for DRS or RAT change.
1009            mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler());
1010
1011            mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler());
1012            mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler());
1013
1014            // Remove ourselves from the DC lists
1015            mDcController.removeDc(DataConnection.this);
1016
1017            if (mAc != null) {
1018                mAc.disconnected();
1019                mAc = null;
1020            }
1021            mApnContexts = null;
1022            mReconnectIntent = null;
1023            mDct = null;
1024            mApnSetting = null;
1025            mPhone = null;
1026            mLinkProperties = null;
1027            mLastFailCause = null;
1028            mUserData = null;
1029            mDcController = null;
1030            mDcTesterFailBringUpAll = null;
1031        }
1032
1033        @Override
1034        public boolean processMessage(Message msg) {
1035            boolean retVal = HANDLED;
1036
1037            if (VDBG) {
1038                log("DcDefault msg=" + getWhatToString(msg.what)
1039                        + " RefCount=" + mApnContexts.size());
1040            }
1041            switch (msg.what) {
1042                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
1043                    if (mAc != null) {
1044                        if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
1045                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
1046                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
1047                    } else {
1048                        mAc = new AsyncChannel();
1049                        mAc.connected(null, getHandler(), msg.replyTo);
1050                        if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
1051                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
1052                                AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
1053                    }
1054                    break;
1055                }
1056                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
1057                    if (DBG) {
1058                        log("DcDefault: CMD_CHANNEL_DISCONNECTED before quiting call dump");
1059                        dumpToLog();
1060                    }
1061
1062                    quit();
1063                    break;
1064                }
1065                case DcAsyncChannel.REQ_IS_INACTIVE: {
1066                    boolean val = getIsInactive();
1067                    if (VDBG) log("REQ_IS_INACTIVE  isInactive=" + val);
1068                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_IS_INACTIVE, val ? 1 : 0);
1069                    break;
1070                }
1071                case DcAsyncChannel.REQ_GET_CID: {
1072                    int cid = getCid();
1073                    if (VDBG) log("REQ_GET_CID  cid=" + cid);
1074                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_CID, cid);
1075                    break;
1076                }
1077                case DcAsyncChannel.REQ_GET_APNSETTING: {
1078                    ApnSetting apnSetting = getApnSetting();
1079                    if (VDBG) log("REQ_GET_APNSETTING  mApnSetting=" + apnSetting);
1080                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_APNSETTING, apnSetting);
1081                    break;
1082                }
1083                case DcAsyncChannel.REQ_GET_LINK_PROPERTIES: {
1084                    LinkProperties lp = getCopyLinkProperties();
1085                    if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
1086                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_PROPERTIES, lp);
1087                    break;
1088                }
1089                case DcAsyncChannel.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
1090                    ProxyInfo proxy = (ProxyInfo) msg.obj;
1091                    if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
1092                    setLinkPropertiesHttpProxy(proxy);
1093                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
1094                    if (mNetworkAgent != null) {
1095                        mNetworkAgent.sendLinkProperties(mLinkProperties);
1096                    }
1097                    break;
1098                }
1099                case DcAsyncChannel.REQ_GET_NETWORK_CAPABILITIES: {
1100                    NetworkCapabilities nc = getCopyNetworkCapabilities();
1101                    if (VDBG) log("REQ_GET_NETWORK_CAPABILITIES networkCapabilities" + nc);
1102                    mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_NETWORK_CAPABILITIES, nc);
1103                    break;
1104                }
1105                case DcAsyncChannel.REQ_RESET:
1106                    if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
1107                    transitionTo(mInactiveState);
1108                    break;
1109                case EVENT_CONNECT:
1110                    if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
1111                    ConnectionParams cp = (ConnectionParams) msg.obj;
1112                    notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false);
1113                    break;
1114
1115                case EVENT_DISCONNECT:
1116                    if (DBG) {
1117                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount="
1118                                + mApnContexts.size());
1119                    }
1120                    deferMessage(msg);
1121                    break;
1122
1123                case EVENT_DISCONNECT_ALL:
1124                    if (DBG) {
1125                        log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount="
1126                                + mApnContexts.size());
1127                    }
1128                    deferMessage(msg);
1129                    break;
1130
1131                case EVENT_TEAR_DOWN_NOW:
1132                    if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW");
1133                    mPhone.mCi.deactivateDataCall(mCid, 0,  null);
1134                    break;
1135
1136                case EVENT_LOST_CONNECTION:
1137                    if (DBG) {
1138                        String s = "DcDefaultState ignore EVENT_LOST_CONNECTION"
1139                                + " tag=" + msg.arg1 + ":mTag=" + mTag;
1140                        logAndAddLogRec(s);
1141                    }
1142                    break;
1143                case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
1144                    AsyncResult ar = (AsyncResult)msg.obj;
1145                    Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
1146                    mDataRegState = drsRatPair.first;
1147                    if (mRilRat != drsRatPair.second) {
1148                        updateTcpBufferSizes(drsRatPair.second);
1149                    }
1150                    mRilRat = drsRatPair.second;
1151                    if (DBG) {
1152                        log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
1153                                + " drs=" + mDataRegState
1154                                + " mRilRat=" + mRilRat);
1155                    }
1156                    ServiceState ss = mPhone.getServiceState();
1157                    int networkType = ss.getDataNetworkType();
1158                    mNetworkInfo.setSubtype(networkType,
1159                            TelephonyManager.getNetworkTypeName(networkType));
1160                    if (mNetworkAgent != null) {
1161                        updateNetworkInfoSuspendState();
1162                        mNetworkAgent.sendNetworkCapabilities(makeNetworkCapabilities());
1163                        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
1164                        mNetworkAgent.sendLinkProperties(mLinkProperties);
1165                    }
1166                    break;
1167
1168                case EVENT_DATA_CONNECTION_ROAM_ON:
1169                    mNetworkInfo.setRoaming(true);
1170                    break;
1171
1172                case EVENT_DATA_CONNECTION_ROAM_OFF:
1173                    mNetworkInfo.setRoaming(false);
1174                    break;
1175
1176                default:
1177                    if (DBG) {
1178                        log("DcDefaultState: shouldn't happen but ignore msg.what="
1179                                + getWhatToString(msg.what));
1180                    }
1181                    break;
1182            }
1183
1184            return retVal;
1185        }
1186    }
1187
1188    private boolean updateNetworkInfoSuspendState() {
1189        final NetworkInfo.DetailedState oldState = mNetworkInfo.getDetailedState();
1190
1191        // this is only called when we are either connected or suspended.  Decide which.
1192        if (mNetworkAgent == null) {
1193            Rlog.e(getName(), "Setting suspend state without a NetworkAgent");
1194        }
1195
1196        // if we are not in-service change to SUSPENDED
1197        final ServiceStateTracker sst = mPhone.getServiceStateTracker();
1198        if (sst.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
1199            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null,
1200                    mNetworkInfo.getExtraInfo());
1201        } else {
1202            // check for voice call and concurrency issues
1203            if (sst.isConcurrentVoiceAndDataAllowed() == false) {
1204                final CallTracker ct = mPhone.getCallTracker();
1205                if (ct.getState() != PhoneConstants.State.IDLE) {
1206                    mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null,
1207                            mNetworkInfo.getExtraInfo());
1208                    return (oldState != NetworkInfo.DetailedState.SUSPENDED);
1209                }
1210            }
1211            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null,
1212                    mNetworkInfo.getExtraInfo());
1213        }
1214        return (oldState != mNetworkInfo.getDetailedState());
1215    }
1216
1217    private DcDefaultState mDefaultState = new DcDefaultState();
1218
1219    /**
1220     * The state machine is inactive and expects a EVENT_CONNECT.
1221     */
1222    private class DcInactiveState extends State {
1223        // Inform all contexts we've failed connecting
1224        public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) {
1225            if (VDBG) log("DcInactiveState: setEnterNotificationParams cp,cause");
1226            mConnectionParams = cp;
1227            mDisconnectParams = null;
1228            mDcFailCause = cause;
1229        }
1230
1231        // Inform all contexts we've failed disconnected
1232        public void setEnterNotificationParams(DisconnectParams dp) {
1233            if (VDBG) log("DcInactiveState: setEnterNotificationParams dp");
1234            mConnectionParams = null;
1235            mDisconnectParams = dp;
1236            mDcFailCause = DcFailCause.NONE;
1237        }
1238
1239        // Inform all contexts of the failure cause
1240        public void setEnterNotificationParams(DcFailCause cause) {
1241            mConnectionParams = null;
1242            mDisconnectParams = null;
1243            mDcFailCause = cause;
1244        }
1245
1246        @Override
1247        public void enter() {
1248            mTag += 1;
1249            if (DBG) log("DcInactiveState: enter() mTag=" + mTag);
1250
1251            if (mConnectionParams != null) {
1252                if (DBG) {
1253                    log("DcInactiveState: enter notifyConnectCompleted +ALL failCause="
1254                            + mDcFailCause);
1255                }
1256                notifyConnectCompleted(mConnectionParams, mDcFailCause, true);
1257            }
1258            if (mDisconnectParams != null) {
1259                if (DBG) {
1260                    log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause="
1261                            + mDcFailCause);
1262                }
1263                notifyDisconnectCompleted(mDisconnectParams, true);
1264            }
1265            if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) {
1266                if (DBG) {
1267                    log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
1268                            + mDcFailCause);
1269                }
1270                notifyAllDisconnectCompleted(mDcFailCause);
1271            }
1272
1273            // Remove ourselves from cid mapping, before clearSettings
1274            mDcController.removeActiveDcByCid(DataConnection.this);
1275
1276            clearSettings();
1277        }
1278
1279        @Override
1280        public void exit() {
1281        }
1282
1283        @Override
1284        public boolean processMessage(Message msg) {
1285            boolean retVal;
1286
1287            switch (msg.what) {
1288                case DcAsyncChannel.REQ_RESET:
1289                    if (DBG) {
1290                        log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
1291                    }
1292                    retVal = HANDLED;
1293                    break;
1294
1295                case EVENT_CONNECT:
1296                    if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
1297                    ConnectionParams cp = (ConnectionParams) msg.obj;
1298                    if (initConnection(cp)) {
1299                        onConnect(mConnectionParams);
1300                        transitionTo(mActivatingState);
1301                    } else {
1302                        if (DBG) {
1303                            log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
1304                        }
1305                        notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
1306                                false);
1307                    }
1308                    retVal = HANDLED;
1309                    break;
1310
1311                case EVENT_DISCONNECT:
1312                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
1313                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
1314                    retVal = HANDLED;
1315                    break;
1316
1317                case EVENT_DISCONNECT_ALL:
1318                    if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
1319                    notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
1320                    retVal = HANDLED;
1321                    break;
1322
1323                default:
1324                    if (VDBG) {
1325                        log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what));
1326                    }
1327                    retVal = NOT_HANDLED;
1328                    break;
1329            }
1330            return retVal;
1331        }
1332    }
1333    private DcInactiveState mInactiveState = new DcInactiveState();
1334
1335    /**
1336     * The state machine is activating a connection.
1337     */
1338    private class DcActivatingState extends State {
1339        @Override
1340        public boolean processMessage(Message msg) {
1341            boolean retVal;
1342            AsyncResult ar;
1343            ConnectionParams cp;
1344
1345            if (DBG) log("DcActivatingState: msg=" + msgToString(msg));
1346            switch (msg.what) {
1347                case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
1348                case EVENT_CONNECT:
1349                    // Activating can't process until we're done.
1350                    deferMessage(msg);
1351                    retVal = HANDLED;
1352                    break;
1353
1354                case EVENT_SETUP_DATA_CONNECTION_DONE:
1355                    ar = (AsyncResult) msg.obj;
1356                    cp = (ConnectionParams) ar.userObj;
1357
1358                    DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);
1359                    if (result != DataCallResponse.SetupResult.ERR_Stale) {
1360                        if (mConnectionParams != cp) {
1361                            loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams
1362                                    + " != cp:" + cp);
1363                        }
1364                    }
1365                    if (DBG) {
1366                        log("DcActivatingState onSetupConnectionCompleted result=" + result
1367                                + " dc=" + DataConnection.this);
1368                    }
1369                    if (cp.mApnContext != null) {
1370                        cp.mApnContext.requestLog("onSetupConnectionCompleted result=" + result);
1371                    }
1372                    switch (result) {
1373                        case SUCCESS:
1374                            // All is well
1375                            mDcFailCause = DcFailCause.NONE;
1376                            transitionTo(mActiveState);
1377                            break;
1378                        case ERR_BadCommand:
1379                            // Vendor ril rejected the command and didn't connect.
1380                            // Transition to inactive but send notifications after
1381                            // we've entered the mInactive state.
1382                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
1383                            transitionTo(mInactiveState);
1384                            break;
1385                        case ERR_UnacceptableParameter:
1386                            // The addresses given from the RIL are bad
1387                            tearDownData(cp);
1388                            transitionTo(mDisconnectingErrorCreatingConnection);
1389                            break;
1390                        case ERR_GetLastErrorFromRil:
1391                            // Request failed and this is an old RIL
1392                            mPhone.mCi.getLastDataCallFailCause(
1393                                    obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
1394                            break;
1395                        case ERR_RilError:
1396
1397                            // Retrieve the suggested retry delay from the modem and save it.
1398                            // If the modem want us to retry the current APN again, it will
1399                            // suggest a positive delay value (in milliseconds). Otherwise we'll get
1400                            // NO_SUGGESTED_RETRY_DELAY here.
1401                            long delay = getSuggestedRetryDelay(ar);
1402                            cp.mApnContext.setModemSuggestedDelay(delay);
1403
1404                            String str = "DcActivatingState: ERR_RilError "
1405                                    + " delay=" + delay
1406                                    + " result=" + result
1407                                    + " result.isRestartRadioFail=" +
1408                                    result.mFailCause.isRestartRadioFail()
1409                                    + " result.isPermanentFail=" +
1410                                    mDct.isPermanentFail(result.mFailCause);
1411                            if (DBG) log(str);
1412                            if (cp.mApnContext != null) cp.mApnContext.requestLog(str);
1413
1414                            // Save the cause. DcTracker.onDataSetupComplete will check this
1415                            // failure cause and determine if we need to retry this APN later
1416                            // or not.
1417                            mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
1418                            transitionTo(mInactiveState);
1419                            break;
1420                        case ERR_Stale:
1421                            loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE"
1422                                    + " tag:" + cp.mTag + " != mTag:" + mTag);
1423                            break;
1424                        default:
1425                            throw new RuntimeException("Unknown SetupResult, should not happen");
1426                    }
1427                    retVal = HANDLED;
1428                    break;
1429
1430                case EVENT_GET_LAST_FAIL_DONE:
1431                    ar = (AsyncResult) msg.obj;
1432                    cp = (ConnectionParams) ar.userObj;
1433                    if (cp.mTag == mTag) {
1434                        if (mConnectionParams != cp) {
1435                            loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams
1436                                    + " != cp:" + cp);
1437                        }
1438
1439                        DcFailCause cause = DcFailCause.UNKNOWN;
1440
1441                        if (ar.exception == null) {
1442                            int rilFailCause = ((int[]) (ar.result))[0];
1443                            cause = DcFailCause.fromInt(rilFailCause);
1444                            if (cause == DcFailCause.NONE) {
1445                                if (DBG) {
1446                                    log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
1447                                            + " BAD: error was NONE, change to UNKNOWN");
1448                                }
1449                                cause = DcFailCause.UNKNOWN;
1450                            }
1451                        }
1452                        mDcFailCause = cause;
1453
1454                        if (DBG) {
1455                            log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"
1456                                    + " cause=" + cause + " dc=" + DataConnection.this);
1457                        }
1458
1459                        mInactiveState.setEnterNotificationParams(cp, cause);
1460                        transitionTo(mInactiveState);
1461                    } else {
1462                        loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE"
1463                                + " tag:" + cp.mTag + " != mTag:" + mTag);
1464                    }
1465
1466                    retVal = HANDLED;
1467                    break;
1468
1469                default:
1470                    if (VDBG) {
1471                        log("DcActivatingState not handled msg.what=" +
1472                                getWhatToString(msg.what) + " RefCount=" + mApnContexts.size());
1473                    }
1474                    retVal = NOT_HANDLED;
1475                    break;
1476            }
1477            return retVal;
1478        }
1479    }
1480    private DcActivatingState mActivatingState = new DcActivatingState();
1481
1482    /**
1483     * The state machine is connected, expecting an EVENT_DISCONNECT.
1484     */
1485    private class DcActiveState extends State {
1486        @Override public void enter() {
1487            if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
1488
1489            boolean createNetworkAgent = true;
1490            // If a disconnect is already pending, avoid notifying all of connected
1491            if (hasMessages(EVENT_DISCONNECT) ||
1492                    hasMessages(EVENT_DISCONNECT_ALL) ||
1493                    hasDeferredMessages(EVENT_DISCONNECT) ||
1494                    hasDeferredMessages(EVENT_DISCONNECT_ALL)) {
1495                log("DcActiveState: skipping notifyAllOfConnected()");
1496                createNetworkAgent = false;
1497            } else {
1498                // If we were retrying there maybe more than one, otherwise they'll only be one.
1499                notifyAllOfConnected(Phone.REASON_CONNECTED);
1500            }
1501
1502            mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(),
1503                    DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null);
1504            mPhone.getCallTracker().registerForVoiceCallEnded(getHandler(),
1505                    DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED, null);
1506
1507            // If the EVENT_CONNECT set the current max retry restore it here
1508            // if it didn't then this is effectively a NOP.
1509            mDcController.addActiveDcByCid(DataConnection.this);
1510
1511            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED,
1512                    mNetworkInfo.getReason(), null);
1513            mNetworkInfo.setExtraInfo(mApnSetting.apn);
1514            updateTcpBufferSizes(mRilRat);
1515
1516            final NetworkMisc misc = new NetworkMisc();
1517            final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent();
1518            if(carrierSignalAgent.hasRegisteredCarrierSignalReceivers()) {
1519                // carrierSignal Receivers will place the carrier-specific provisioning notification
1520                misc.provisioningNotificationDisabled = true;
1521            }
1522            misc.subscriberId = mPhone.getSubscriberId();
1523
1524            if (createNetworkAgent) {
1525                mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
1526                        "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
1527                        50, misc);
1528            }
1529        }
1530
1531        @Override
1532        public void exit() {
1533            if (DBG) log("DcActiveState: exit dc=" + this);
1534            String reason = mNetworkInfo.getReason();
1535            if(mDcController.isExecutingCarrierChange()) {
1536                reason = Phone.REASON_CARRIER_CHANGE;
1537            } else if (mDisconnectParams != null && mDisconnectParams.mReason != null) {
1538                reason = mDisconnectParams.mReason;
1539            } else if (mDcFailCause != null) {
1540                reason = mDcFailCause.toString();
1541            }
1542            mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler());
1543            mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler());
1544
1545            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
1546                    reason, mNetworkInfo.getExtraInfo());
1547            if (mNetworkAgent != null) {
1548                mNetworkAgent.sendNetworkInfo(mNetworkInfo);
1549                mNetworkAgent = null;
1550            }
1551        }
1552
1553        @Override
1554        public boolean processMessage(Message msg) {
1555            boolean retVal;
1556
1557            switch (msg.what) {
1558                case EVENT_CONNECT: {
1559                    ConnectionParams cp = (ConnectionParams) msg.obj;
1560                    // either add this new apn context to our set or
1561                    // update the existing cp with the latest connection generation number
1562                    mApnContexts.put(cp.mApnContext, cp);
1563                    if (DBG) {
1564                        log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this);
1565                    }
1566                    notifyConnectCompleted(cp, DcFailCause.NONE, false);
1567                    retVal = HANDLED;
1568                    break;
1569                }
1570                case EVENT_DISCONNECT: {
1571                    DisconnectParams dp = (DisconnectParams) msg.obj;
1572                    if (DBG) {
1573                        log("DcActiveState: EVENT_DISCONNECT dp=" + dp
1574                                + " dc=" + DataConnection.this);
1575                    }
1576                    if (mApnContexts.containsKey(dp.mApnContext)) {
1577                        if (DBG) {
1578                            log("DcActiveState msg.what=EVENT_DISCONNECT RefCount="
1579                                    + mApnContexts.size());
1580                        }
1581
1582                        if (mApnContexts.size() == 1) {
1583                            mApnContexts.clear();
1584                            mDisconnectParams = dp;
1585                            mConnectionParams = null;
1586                            dp.mTag = mTag;
1587                            tearDownData(dp);
1588                            transitionTo(mDisconnectingState);
1589                        } else {
1590                            mApnContexts.remove(dp.mApnContext);
1591                            notifyDisconnectCompleted(dp, false);
1592                        }
1593                    } else {
1594                        log("DcActiveState ERROR no such apnContext=" + dp.mApnContext
1595                                + " in this dc=" + DataConnection.this);
1596                        notifyDisconnectCompleted(dp, false);
1597                    }
1598                    retVal = HANDLED;
1599                    break;
1600                }
1601                case EVENT_DISCONNECT_ALL: {
1602                    if (DBG) {
1603                        log("DcActiveState EVENT_DISCONNECT clearing apn contexts,"
1604                                + " dc=" + DataConnection.this);
1605                    }
1606                    DisconnectParams dp = (DisconnectParams) msg.obj;
1607                    mDisconnectParams = dp;
1608                    mConnectionParams = null;
1609                    dp.mTag = mTag;
1610                    tearDownData(dp);
1611                    transitionTo(mDisconnectingState);
1612                    retVal = HANDLED;
1613                    break;
1614                }
1615                case EVENT_LOST_CONNECTION: {
1616                    if (DBG) {
1617                        log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this);
1618                    }
1619
1620                    mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
1621                    transitionTo(mInactiveState);
1622                    retVal = HANDLED;
1623                    break;
1624                }
1625                case EVENT_DATA_CONNECTION_ROAM_ON: {
1626                    mNetworkInfo.setRoaming(true);
1627                    if (mNetworkAgent != null) {
1628                        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
1629                    }
1630                    retVal = HANDLED;
1631                    break;
1632                }
1633                case EVENT_DATA_CONNECTION_ROAM_OFF: {
1634                    mNetworkInfo.setRoaming(false);
1635                    if (mNetworkAgent != null) {
1636                        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
1637                    }
1638                    retVal = HANDLED;
1639                    break;
1640                }
1641                case EVENT_BW_REFRESH_RESPONSE: {
1642                    AsyncResult ar = (AsyncResult)msg.obj;
1643                    if (ar.exception != null) {
1644                        log("EVENT_BW_REFRESH_RESPONSE: error ignoring, e=" + ar.exception);
1645                    } else {
1646                        final ArrayList<Integer> capInfo = (ArrayList<Integer>)ar.result;
1647                        final int lceBwDownKbps = capInfo.get(0);
1648                        NetworkCapabilities nc = makeNetworkCapabilities();
1649                        if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) {
1650                            nc.setLinkDownstreamBandwidthKbps(lceBwDownKbps);
1651                            if (mNetworkAgent != null) {
1652                                mNetworkAgent.sendNetworkCapabilities(nc);
1653                            }
1654                        }
1655                    }
1656                    retVal = HANDLED;
1657                    break;
1658                }
1659                case EVENT_DATA_CONNECTION_VOICE_CALL_STARTED:
1660                case EVENT_DATA_CONNECTION_VOICE_CALL_ENDED: {
1661                    if (updateNetworkInfoSuspendState() && mNetworkAgent != null) {
1662                        // state changed
1663                        mNetworkAgent.sendNetworkInfo(mNetworkInfo);
1664                    }
1665                    retVal = HANDLED;
1666                    break;
1667                }
1668                default:
1669                    if (VDBG) {
1670                        log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
1671                    }
1672                    retVal = NOT_HANDLED;
1673                    break;
1674            }
1675            return retVal;
1676        }
1677    }
1678    private DcActiveState mActiveState = new DcActiveState();
1679
1680    /**
1681     * The state machine is disconnecting.
1682     */
1683    private class DcDisconnectingState extends State {
1684        @Override
1685        public boolean processMessage(Message msg) {
1686            boolean retVal;
1687
1688            switch (msg.what) {
1689                case EVENT_CONNECT:
1690                    if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
1691                            + mApnContexts.size());
1692                    deferMessage(msg);
1693                    retVal = HANDLED;
1694                    break;
1695
1696                case EVENT_DEACTIVATE_DONE:
1697                    AsyncResult ar = (AsyncResult) msg.obj;
1698                    DisconnectParams dp = (DisconnectParams) ar.userObj;
1699
1700                    String str = "DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount="
1701                            + mApnContexts.size();
1702                    if (DBG) log(str);
1703                    if (dp.mApnContext != null) dp.mApnContext.requestLog(str);
1704
1705                    if (dp.mTag == mTag) {
1706                        // Transition to inactive but send notifications after
1707                        // we've entered the mInactive state.
1708                        mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
1709                        transitionTo(mInactiveState);
1710                    } else {
1711                        if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE"
1712                                + " dp.tag=" + dp.mTag + " mTag=" + mTag);
1713                    }
1714                    retVal = HANDLED;
1715                    break;
1716
1717                default:
1718                    if (VDBG) {
1719                        log("DcDisconnectingState not handled msg.what="
1720                                + getWhatToString(msg.what));
1721                    }
1722                    retVal = NOT_HANDLED;
1723                    break;
1724            }
1725            return retVal;
1726        }
1727    }
1728    private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
1729
1730    /**
1731     * The state machine is disconnecting after an creating a connection.
1732     */
1733    private class DcDisconnectionErrorCreatingConnection extends State {
1734        @Override
1735        public boolean processMessage(Message msg) {
1736            boolean retVal;
1737
1738            switch (msg.what) {
1739                case EVENT_DEACTIVATE_DONE:
1740                    AsyncResult ar = (AsyncResult) msg.obj;
1741                    ConnectionParams cp = (ConnectionParams) ar.userObj;
1742                    if (cp.mTag == mTag) {
1743                        String str = "DcDisconnectionErrorCreatingConnection" +
1744                                " msg.what=EVENT_DEACTIVATE_DONE";
1745                        if (DBG) log(str);
1746                        if (cp.mApnContext != null) cp.mApnContext.requestLog(str);
1747
1748                        // Transition to inactive but send notifications after
1749                        // we've entered the mInactive state.
1750                        mInactiveState.setEnterNotificationParams(cp,
1751                                DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
1752                        transitionTo(mInactiveState);
1753                    } else {
1754                        if (DBG) {
1755                            log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE"
1756                                    + " dp.tag=" + cp.mTag + ", mTag=" + mTag);
1757                        }
1758                    }
1759                    retVal = HANDLED;
1760                    break;
1761
1762                default:
1763                    if (VDBG) {
1764                        log("DcDisconnectionErrorCreatingConnection not handled msg.what="
1765                                + getWhatToString(msg.what));
1766                    }
1767                    retVal = NOT_HANDLED;
1768                    break;
1769            }
1770            return retVal;
1771        }
1772    }
1773    private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
1774                new DcDisconnectionErrorCreatingConnection();
1775
1776
1777    private class DcNetworkAgent extends NetworkAgent {
1778        public DcNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
1779                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
1780            super(l, c, TAG, ni, nc, lp, score, misc);
1781        }
1782
1783        @Override
1784        protected void unwanted() {
1785            if (mNetworkAgent != this) {
1786                log("DcNetworkAgent: unwanted found mNetworkAgent=" + mNetworkAgent +
1787                        ", which isn't me.  Aborting unwanted");
1788                return;
1789            }
1790            // this can only happen if our exit has been called - we're already disconnected
1791            if (mApnContexts == null) return;
1792            for (ConnectionParams cp : mApnContexts.values()) {
1793                final ApnContext apnContext = cp.mApnContext;
1794                final Pair<ApnContext, Integer> pair =
1795                        new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
1796                log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext);
1797                Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
1798                DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg);
1799                DataConnection.this.sendMessage(DataConnection.this.
1800                        obtainMessage(EVENT_DISCONNECT, dp));
1801            }
1802        }
1803
1804        @Override
1805        protected void pollLceData() {
1806            if(mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) {  // active LCE service
1807                mPhone.mCi.pullLceData(DataConnection.this.obtainMessage(EVENT_BW_REFRESH_RESPONSE));
1808            }
1809        }
1810
1811        @Override
1812        protected void networkStatus(int status, String redirectUrl) {
1813            if(!TextUtils.isEmpty(redirectUrl)) {
1814                log("validation status: " + status + " with redirection URL: " + redirectUrl);
1815                /* its possible that we have multiple DataConnection with INTERNET_CAPABILITY
1816                   all fail the validation with the same redirection url, send CMD back to DCTracker
1817                   and let DcTracker to make the decision */
1818                Message msg = mDct.obtainMessage(DctConstants.EVENT_REDIRECTION_DETECTED,
1819                        redirectUrl);
1820                msg.sendToTarget();
1821            }
1822        }
1823    }
1824
1825    // ******* "public" interface
1826
1827    /**
1828     * Used for testing purposes.
1829     */
1830    /* package */ void tearDownNow() {
1831        if (DBG) log("tearDownNow()");
1832        sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW));
1833    }
1834
1835    /**
1836     * Using the result of the SETUP_DATA_CALL determine the retry delay.
1837     *
1838     * @param ar is the result from SETUP_DATA_CALL
1839     * @return NO_SUGGESTED_RETRY_DELAY if no retry is needed otherwise the delay to the
1840     *         next SETUP_DATA_CALL
1841     */
1842    private long getSuggestedRetryDelay(AsyncResult ar) {
1843
1844        DataCallResponse response = (DataCallResponse) ar.result;
1845
1846        /** According to ril.h
1847         * The value < 0 means no value is suggested
1848         * The value 0 means retry should be done ASAP.
1849         * The value of Integer.MAX_VALUE(0x7fffffff) means no retry.
1850         */
1851
1852        // The value < 0 means no value is suggested
1853        if (response.suggestedRetryTime < 0) {
1854            if (DBG) log("No suggested retry delay.");
1855            return RetryManager.NO_SUGGESTED_RETRY_DELAY;
1856        }
1857        // The value of Integer.MAX_VALUE(0x7fffffff) means no retry.
1858        else if (response.suggestedRetryTime == Integer.MAX_VALUE) {
1859            if (DBG) log("Modem suggested not retrying.");
1860            return RetryManager.NO_RETRY;
1861        }
1862
1863        // We need to cast it to long because the value returned from RIL is a 32-bit integer,
1864        // but the time values used in AlarmManager are all 64-bit long.
1865        return (long) response.suggestedRetryTime;
1866    }
1867
1868    /**
1869     * @return the string for msg.what as our info.
1870     */
1871    @Override
1872    protected String getWhatToString(int what) {
1873        return cmdToString(what);
1874    }
1875
1876    private static String msgToString(Message msg) {
1877        String retVal;
1878        if (msg == null) {
1879            retVal = "null";
1880        } else {
1881            StringBuilder   b = new StringBuilder();
1882
1883            b.append("{what=");
1884            b.append(cmdToString(msg.what));
1885
1886            b.append(" when=");
1887            TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b);
1888
1889            if (msg.arg1 != 0) {
1890                b.append(" arg1=");
1891                b.append(msg.arg1);
1892            }
1893
1894            if (msg.arg2 != 0) {
1895                b.append(" arg2=");
1896                b.append(msg.arg2);
1897            }
1898
1899            if (msg.obj != null) {
1900                b.append(" obj=");
1901                b.append(msg.obj);
1902            }
1903
1904            b.append(" target=");
1905            b.append(msg.getTarget());
1906
1907            b.append(" replyTo=");
1908            b.append(msg.replyTo);
1909
1910            b.append("}");
1911
1912            retVal = b.toString();
1913        }
1914        return retVal;
1915    }
1916
1917    static void slog(String s) {
1918        Rlog.d("DC", s);
1919    }
1920
1921    /**
1922     * Log with debug
1923     *
1924     * @param s is string log
1925     */
1926    @Override
1927    protected void log(String s) {
1928        Rlog.d(getName(), s);
1929    }
1930
1931    /**
1932     * Log with debug attribute
1933     *
1934     * @param s is string log
1935     */
1936    @Override
1937    protected void logd(String s) {
1938        Rlog.d(getName(), s);
1939    }
1940
1941    /**
1942     * Log with verbose attribute
1943     *
1944     * @param s is string log
1945     */
1946    @Override
1947    protected void logv(String s) {
1948        Rlog.v(getName(), s);
1949    }
1950
1951    /**
1952     * Log with info attribute
1953     *
1954     * @param s is string log
1955     */
1956    @Override
1957    protected void logi(String s) {
1958        Rlog.i(getName(), s);
1959    }
1960
1961    /**
1962     * Log with warning attribute
1963     *
1964     * @param s is string log
1965     */
1966    @Override
1967    protected void logw(String s) {
1968        Rlog.w(getName(), s);
1969    }
1970
1971    /**
1972     * Log with error attribute
1973     *
1974     * @param s is string log
1975     */
1976    @Override
1977    protected void loge(String s) {
1978        Rlog.e(getName(), s);
1979    }
1980
1981    /**
1982     * Log with error attribute
1983     *
1984     * @param s is string log
1985     * @param e is a Throwable which logs additional information.
1986     */
1987    @Override
1988    protected void loge(String s, Throwable e) {
1989        Rlog.e(getName(), s, e);
1990    }
1991
1992    /** Doesn't print mApnList of ApnContext's which would be recursive */
1993    public String toStringSimple() {
1994        return getName() + ": State=" + getCurrentState().getName()
1995                + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size()
1996                + " mCid=" + mCid + " mCreateTime=" + mCreateTime
1997                + " mLastastFailTime=" + mLastFailTime
1998                + " mLastFailCause=" + mLastFailCause
1999                + " mTag=" + mTag
2000                + " mLinkProperties=" + mLinkProperties
2001                + " linkCapabilities=" + makeNetworkCapabilities();
2002    }
2003
2004    @Override
2005    public String toString() {
2006        return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}";
2007    }
2008
2009    private void dumpToLog() {
2010        dump(null, new PrintWriter(new StringWriter(0)) {
2011            @Override
2012            public void println(String s) {
2013                DataConnection.this.logd(s);
2014            }
2015
2016            @Override
2017            public void flush() {
2018            }
2019        }, null);
2020    }
2021
2022    /**
2023     * Dump the current state.
2024     *
2025     * @param fd
2026     * @param pw
2027     * @param args
2028     */
2029    @Override
2030    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2031        pw.print("DataConnection ");
2032        super.dump(fd, pw, args);
2033        pw.println(" mApnContexts.size=" + mApnContexts.size());
2034        pw.println(" mApnContexts=" + mApnContexts);
2035        pw.flush();
2036        pw.println(" mDataConnectionTracker=" + mDct);
2037        pw.println(" mApnSetting=" + mApnSetting);
2038        pw.println(" mTag=" + mTag);
2039        pw.println(" mCid=" + mCid);
2040        pw.println(" mConnectionParams=" + mConnectionParams);
2041        pw.println(" mDisconnectParams=" + mDisconnectParams);
2042        pw.println(" mDcFailCause=" + mDcFailCause);
2043        pw.flush();
2044        pw.println(" mPhone=" + mPhone);
2045        pw.flush();
2046        pw.println(" mLinkProperties=" + mLinkProperties);
2047        pw.flush();
2048        pw.println(" mDataRegState=" + mDataRegState);
2049        pw.println(" mRilRat=" + mRilRat);
2050        pw.println(" mNetworkCapabilities=" + makeNetworkCapabilities());
2051        pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
2052        pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
2053        pw.println(" mLastFailCause=" + mLastFailCause);
2054        pw.flush();
2055        pw.println(" mUserData=" + mUserData);
2056        pw.println(" mInstanceNumber=" + mInstanceNumber);
2057        pw.println(" mAc=" + mAc);
2058        pw.flush();
2059    }
2060}
2061
2062