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