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