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