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