2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony;
20 import com.android.internal.telephony.DataCallState.SetupResult;
21 import com.android.internal.util.AsyncChannel;
22 import com.android.internal.util.Protocol;
23 import com.android.internal.util.State;
24 import com.android.internal.util.StateMachine;
26 import android.app.PendingIntent;
27 import android.net.LinkCapabilities;
28 import android.net.LinkProperties;
29 import android.net.ProxyProperties;
30 import android.os.AsyncResult;
31 import android.os.Message;
32 import android.os.SystemProperties;
33 import android.text.TextUtils;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
42 * DataConnection StateMachine.
44 * This is an abstract base class for representing a single data connection.
45 * Instances of this class such as <code>CdmaDataConnection</code> and
46 * <code>GsmDataConnection</code>, * represent a connection via the cellular network.
47 * There may be multiple data connections and all of them are managed by the
48 * <code>DataConnectionTracker</code>.
50 * Instances are asynchronous state machines and have two primary entry points
51 * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
52 * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
53 * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
54 * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
55 * If an error <code>AsyncResult.result = FailCause</code> and
56 * <code>AsyncResult.exception = new Exception()</code>.
58 * The other public methods are provided for debugging.
60 public abstract class DataConnection extends StateMachine {
61 protected static final boolean DBG = true;
62 protected static final boolean VDBG = false;
64 protected static Object mCountLock = new Object();
65 protected static int mCount;
66 protected AsyncChannel mAc;
68 private List<ApnContext> mApnList = null;
69 PendingIntent mReconnectIntent = null;
72 * Used internally for saving connecting parameters.
74 protected static class ConnectionParams {
75 public ConnectionParams(ApnSetting apn, Message onCompletedMsg) {
77 this.onCompletedMsg = onCompletedMsg;
81 public ApnSetting apn;
82 public Message onCompletedMsg;
86 * Used internally for saving disconnecting parameters.
88 protected static class DisconnectParams {
89 public DisconnectParams(String reason, Message onCompletedMsg) {
91 this.onCompletedMsg = onCompletedMsg;
95 public Message onCompletedMsg;
99 * Returned as the reason for a connection failure as defined
100 * by RIL_DataCallFailCause in ril.h and some local errors.
102 public enum FailCause {
105 // This series of errors as specified by the standards
106 // specified in ril.h
107 OPERATOR_BARRED(0x08),
108 INSUFFICIENT_RESOURCES(0x1A),
109 MISSING_UNKNOWN_APN(0x1B),
110 UNKNOWN_PDP_ADDRESS_TYPE(0x1C),
111 USER_AUTHENTICATION(0x1D),
112 ACTIVATION_REJECT_GGSN(0x1E),
113 ACTIVATION_REJECT_UNSPECIFIED(0x1F),
114 SERVICE_OPTION_NOT_SUPPORTED(0x20),
115 SERVICE_OPTION_NOT_SUBSCRIBED(0x21),
116 SERVICE_OPTION_OUT_OF_ORDER(0x22),
118 ONLY_IPV4_ALLOWED(0x32),
119 ONLY_IPV6_ALLOWED(0x33),
120 ONLY_SINGLE_BEARER_ALLOWED(0x34),
121 PROTOCOL_ERRORS(0x6F),
123 // Local errors generated by Vendor RIL
124 // specified in ril.h
125 REGISTRATION_FAIL(-1),
126 GPRS_REGISTRATION_FAIL(-2),
128 PREF_RADIO_TECH_CHANGED(-4),
130 TETHERED_CALL_ACTIVE(-6),
131 ERROR_UNSPECIFIED(0xFFFF),
133 // Errors generated by the Framework
136 RADIO_NOT_AVAILABLE(0x10001),
137 UNACCEPTABLE_NETWORK_PARAMETER(0x10002);
139 private final int mErrorCode;
140 private static final HashMap<Integer, FailCause> sErrorCodeToFailCauseMap;
142 sErrorCodeToFailCauseMap = new HashMap<Integer, FailCause>();
143 for (FailCause fc : values()) {
144 sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
148 FailCause(int errorCode) {
149 mErrorCode = errorCode;
156 public boolean isPermanentFail() {
157 return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
158 (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
159 (this == SERVICE_OPTION_NOT_SUPPORTED) ||
160 (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||
161 (this == PROTOCOL_ERRORS);
164 public boolean isEventLoggable() {
165 return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
166 (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
167 (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
168 (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
169 (this == SERVICE_OPTION_NOT_SUPPORTED) ||
170 (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
171 (this == PROTOCOL_ERRORS) ||
172 (this == UNACCEPTABLE_NETWORK_PARAMETER);
175 public static FailCause fromInt(int errorCode) {
176 FailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
184 public static class CallSetupException extends Exception {
185 private int mRetryOverride = -1;
187 CallSetupException (int retryOverride) {
188 mRetryOverride = retryOverride;
191 public int getRetryOverride() {
192 return mRetryOverride;
196 // ***** Event codes for driving the state machine
197 protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
198 protected static final int EVENT_CONNECT = BASE + 0;
199 protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
200 protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
201 protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
202 protected static final int EVENT_DISCONNECT = BASE + 4;
203 protected static final int EVENT_RIL_CONNECTED = BASE + 5;
205 //***** Tag IDs for EventLog
206 protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
208 //***** Member Variables
209 protected ApnSetting mApn;
211 protected PhoneBase phone;
212 protected int mRilVersion = -1;
214 protected LinkProperties mLinkProperties = new LinkProperties();
215 protected LinkCapabilities mCapabilities = new LinkCapabilities();
216 protected long createTime;
217 protected long lastFailTime;
218 protected FailCause lastFailCause;
219 protected int mRetryOverride = -1;
220 protected static final String NULL_IP = "0.0.0.0";
221 private int mRefCount;
224 //***** Abstract methods
226 public abstract String toString();
228 protected abstract void onConnect(ConnectionParams cp);
230 protected abstract boolean isDnsOk(String[] domainNameServers);
232 protected abstract void log(String s);
236 protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm) {
238 if (DBG) log("DataConnection constructor E");
245 addState(mDefaultState);
246 addState(mInactiveState, mDefaultState);
247 addState(mActivatingState, mDefaultState);
248 addState(mActiveState, mDefaultState);
249 addState(mDisconnectingState, mDefaultState);
250 addState(mDisconnectingErrorCreatingConnection, mDefaultState);
251 setInitialState(mInactiveState);
253 mApnList = new ArrayList<ApnContext>();
254 if (DBG) log("DataConnection constructor X");
258 * TearDown the data connection.
260 * @param o will be returned in AsyncResult.userObj
261 * and is either a DisconnectParams or ConnectionParams.
263 private void tearDownData(Object o) {
264 int discReason = RILConstants.DEACTIVATE_REASON_NONE;
265 if ((o != null) && (o instanceof DisconnectParams)) {
266 DisconnectParams dp = (DisconnectParams)o;
267 Message m = dp.onCompletedMsg;
268 if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
269 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
270 } else if (TextUtils.equals(dp.reason, Phone.REASON_PDP_RESET)) {
271 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
274 if (phone.mCM.getRadioState().isOn()) {
275 if (DBG) log("tearDownData radio is on, call deactivateDataCall");
276 phone.mCM.deactivateDataCall(cid, discReason, obtainMessage(EVENT_DEACTIVATE_DONE, o));
278 if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
279 AsyncResult ar = new AsyncResult(o, null, null);
280 sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar));
285 * Send the connectionCompletedMsg.
287 * @param cp is the ConnectionParams
290 private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
291 Message connectionCompletedMsg = cp.onCompletedMsg;
292 if (connectionCompletedMsg == null) {
296 long timeStamp = System.currentTimeMillis();
297 connectionCompletedMsg.arg1 = cid;
299 if (cause == FailCause.NONE) {
300 createTime = timeStamp;
301 AsyncResult.forMessage(connectionCompletedMsg);
303 lastFailCause = cause;
304 lastFailTime = timeStamp;
305 AsyncResult.forMessage(connectionCompletedMsg, cause,
306 new CallSetupException(mRetryOverride));
308 if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause);
310 connectionCompletedMsg.sendToTarget();
314 * Send ar.userObj if its a message, which is should be back to originator.
316 * @param dp is the DisconnectParams.
318 private void notifyDisconnectCompleted(DisconnectParams dp) {
319 if (VDBG) log("NotifyDisconnectCompleted");
321 if (dp.onCompletedMsg != null) {
322 Message msg = dp.onCompletedMsg;
324 log(String.format("msg=%s msg.obj=%s", msg.toString(),
325 ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>")));
327 AsyncResult.forMessage(msg);
330 if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
333 protected int getRadioTechnology(int defaultRadioTechnology) {
335 if (mRilVersion < 6) {
336 radioTechnology = defaultRadioTechnology;
338 radioTechnology = phone.getServiceState().getRadioTechnology() + 2;
340 return radioTechnology;
344 * **************************************************************************
345 * Begin Members and methods owned by DataConnectionTracker but stored
346 * in a DataConnection because there is one per connection.
347 * **************************************************************************
351 * The id is owned by DataConnectionTracker.
356 * Get the DataConnection ID
358 public int getDataConnectionId() {
363 * The retry manager is currently owned by the DataConnectionTracker but is stored
364 * in the DataConnection because there is one per connection. These methods
365 * should only be used by the DataConnectionTracker although someday the retrying
366 * maybe managed by the DataConnection itself and these methods could disappear.
368 private RetryManager mRetryMgr;
371 * @return retry manager retryCount
373 public int getRetryCount() {
374 return mRetryMgr.getRetryCount();
378 * @return retry manager retryTimer
380 public int getRetryTimer() {
381 return mRetryMgr.getRetryTimer();
385 * increaseRetryCount of retry manager
387 public void increaseRetryCount() {
388 mRetryMgr.increaseRetryCount();
392 * @return retry manager isRetryNeeded
394 public boolean isRetryNeeded() {
395 return mRetryMgr.isRetryNeeded();
399 * resetRetryCount of retry manager
401 public void resetRetryCount() {
402 mRetryMgr.resetRetryCount();
406 * set retryForeverUsingLasttimeout of retry manager
408 public void retryForeverUsingLastTimeout() {
409 mRetryMgr.retryForeverUsingLastTimeout();
413 * @return retry manager isRetryForever
415 public boolean isRetryForever() {
416 return mRetryMgr.isRetryForever();
420 * @return whether the retry config is set successfully or not
422 public boolean configureRetry(int maxRetryCount, int retryTime, int randomizationTime) {
423 return mRetryMgr.configure(maxRetryCount, retryTime, randomizationTime);
427 * @return whether the retry config is set successfully or not
429 public boolean configureRetry(String configStr) {
430 return mRetryMgr.configure(configStr);
434 * **************************************************************************
435 * End members owned by DataConnectionTracker
436 * **************************************************************************
440 * Clear all settings called when entering mInactiveState.
442 protected void clearSettings() {
443 if (DBG) log("clearSettings");
447 lastFailCause = FailCause.NONE;
452 mLinkProperties = new LinkProperties();
457 * Process setup completion.
459 * @param ar is the result
460 * @return SetupResult.
462 private DataCallState.SetupResult onSetupConnectionCompleted(AsyncResult ar) {
463 DataCallState response = (DataCallState) ar.result;
464 ConnectionParams cp = (ConnectionParams) ar.userObj;
465 DataCallState.SetupResult result;
467 if (ar.exception != null) {
469 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception +
470 " response=" + response);
473 if (ar.exception instanceof CommandException
474 && ((CommandException) (ar.exception)).getCommandError()
475 == CommandException.Error.RADIO_NOT_AVAILABLE) {
476 result = DataCallState.SetupResult.ERR_BadCommand;
477 result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
478 } else if ((response == null) || (response.version < 4)) {
479 result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;
481 result = DataCallState.SetupResult.ERR_RilError;
482 result.mFailCause = FailCause.fromInt(response.status);
484 } else if (cp.tag != mTag) {
486 log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
488 result = DataCallState.SetupResult.ERR_Stale;
489 } else if (response.status != 0) {
490 result = DataCallState.SetupResult.ERR_RilError;
491 result.mFailCause = FailCause.fromInt(response.status);
493 if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
495 result = updateLinkProperty(response).setupResult;
501 private int getSuggestedRetryTime(AsyncResult ar) {
503 if (ar.exception == null) {
504 DataCallState response = (DataCallState) ar.result;
505 retry = response.suggestedRetryTime;
510 private DataCallState.SetupResult setLinkProperties(DataCallState response,
512 // Check if system property dns usable
513 boolean okToUseSystemPropertyDns = false;
514 String propertyPrefix = "net." + response.ifname + ".";
515 String dnsServers[] = new String[2];
516 dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
517 dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
518 okToUseSystemPropertyDns = isDnsOk(dnsServers);
520 // set link properties based on data call response
521 return response.setLinkProperties(lp, okToUseSystemPropertyDns);
524 public static class UpdateLinkPropertyResult {
525 public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
526 public LinkProperties oldLp;
527 public LinkProperties newLp;
528 public UpdateLinkPropertyResult(LinkProperties curLp) {
534 private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
535 UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
537 if (newState == null) return result;
539 DataCallState.SetupResult setupResult;
540 result.newLp = new LinkProperties();
542 // set link properties based on data call response
543 result.setupResult = setLinkProperties(newState, result.newLp);
544 if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
545 if (DBG) log("updateLinkProperty failed : " + result.setupResult);
548 // copy HTTP proxy as it is not part DataCallState.
549 result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
551 if (DBG && (! result.oldLp.equals(result.newLp))) {
552 if (DBG) log("updateLinkProperty old != new");
553 if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
554 if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
556 mLinkProperties = result.newLp;
562 * The parent state for all other states.
564 private class DcDefaultState extends State {
566 public void enter() {
567 phone.mCM.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null);
571 phone.mCM.unregisterForRilConnected(getHandler());
574 public boolean processMessage(Message msg) {
578 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
580 if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
581 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
582 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
584 mAc = new AsyncChannel();
585 mAc.connected(null, getHandler(), msg.replyTo);
586 if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
587 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
588 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
592 case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
593 if (VDBG) log("CMD_CHANNEL_DISCONNECT");
597 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
598 if (VDBG) log("CMD_CHANNEL_DISCONNECTED");
602 case DataConnectionAc.REQ_IS_INACTIVE: {
603 boolean val = getCurrentState() == mInactiveState;
604 if (VDBG) log("REQ_IS_INACTIVE isInactive=" + val);
605 mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
608 case DataConnectionAc.REQ_GET_CID: {
609 if (VDBG) log("REQ_GET_CID cid=" + cid);
610 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
613 case DataConnectionAc.REQ_GET_APNSETTING: {
614 if (VDBG) log("REQ_GET_APNSETTING apnSetting=" + mApn);
615 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
618 case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
619 LinkProperties lp = new LinkProperties(mLinkProperties);
620 if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
621 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
624 case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
625 ProxyProperties proxy = (ProxyProperties) msg.obj;
626 if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
627 mLinkProperties.setHttpProxy(proxy);
628 mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
631 case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
632 DataCallState newState = (DataCallState) msg.obj;
633 UpdateLinkPropertyResult result =
634 updateLinkProperty(newState);
636 log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
637 + result + " newState=" + newState);
639 mAc.replyToMessage(msg,
640 DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
644 case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
645 LinkCapabilities lc = new LinkCapabilities(mCapabilities);
646 if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
647 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
650 case DataConnectionAc.REQ_RESET:
651 if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
652 mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
653 transitionTo(mInactiveState);
655 case DataConnectionAc.REQ_GET_REFCOUNT: {
656 if (VDBG) log("REQ_GET_REFCOUNT refCount=" + mRefCount);
657 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount);
660 case DataConnectionAc.REQ_ADD_APNCONTEXT: {
661 ApnContext apnContext = (ApnContext) msg.obj;
662 if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType());
663 if (!mApnList.contains(apnContext)) {
664 mApnList.add(apnContext);
666 mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT);
669 case DataConnectionAc.REQ_REMOVE_APNCONTEXT: {
670 ApnContext apnContext = (ApnContext) msg.obj;
671 if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType());
672 mApnList.remove(apnContext);
673 mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT);
676 case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
677 if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
678 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
679 new ArrayList<ApnContext>(mApnList));
682 case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
683 PendingIntent intent = (PendingIntent) msg.obj;
684 if (VDBG) log("REQ_SET_RECONNECT_INTENT");
685 mReconnectIntent = intent;
686 mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT);
689 case DataConnectionAc.REQ_GET_RECONNECT_INTENT: {
690 if (VDBG) log("REQ_GET_RECONNECT_INTENT");
691 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT,
696 if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
697 ConnectionParams cp = (ConnectionParams) msg.obj;
698 notifyConnectCompleted(cp, FailCause.UNKNOWN);
701 case EVENT_DISCONNECT:
702 if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT");
703 notifyDisconnectCompleted((DisconnectParams) msg.obj);
706 case EVENT_RIL_CONNECTED:
707 ar = (AsyncResult)msg.obj;
708 if (ar.exception == null) {
709 mRilVersion = (Integer)ar.result;
711 log("DcDefaultState: msg.what=EVENT_RIL_CONNECTED mRilVersion=" +
715 log("Unexpected exception on EVENT_RIL_CONNECTED");
722 log("DcDefaultState: shouldn't happen but ignore msg.what=0x" +
723 Integer.toHexString(msg.what));
731 private DcDefaultState mDefaultState = new DcDefaultState();
734 * The state machine is inactive and expects a EVENT_CONNECT.
736 private class DcInactiveState extends State {
737 private ConnectionParams mConnectionParams = null;
738 private FailCause mFailCause = null;
739 private DisconnectParams mDisconnectParams = null;
741 public void setEnterNotificationParams(ConnectionParams cp, FailCause cause,
743 if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
744 mConnectionParams = cp;
746 mRetryOverride = retryOverride;
749 public void setEnterNotificationParams(DisconnectParams dp) {
750 if (VDBG) log("DcInactiveState: setEnterNoticationParams dp");
751 mDisconnectParams = dp;
755 public void enter() {
759 * Now that we've transitioned to Inactive state we
760 * can send notifications. Previously we sent the
761 * notifications in the processMessage handler but
762 * that caused a race condition because the synchronous
763 * call to isInactive.
765 if ((mConnectionParams != null) && (mFailCause != null)) {
766 if (VDBG) log("DcInactiveState: enter notifyConnectCompleted");
767 notifyConnectCompleted(mConnectionParams, mFailCause);
769 if (mDisconnectParams != null) {
770 if (VDBG) log("DcInactiveState: enter notifyDisconnectCompleted");
771 notifyDisconnectCompleted(mDisconnectParams);
778 // clear notifications
779 mConnectionParams = null;
781 mDisconnectParams = null;
785 public boolean processMessage(Message msg) {
789 case DataConnectionAc.REQ_RESET:
791 log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
793 mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
798 ConnectionParams cp = (ConnectionParams) msg.obj;
801 log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = "
806 transitionTo(mActivatingState);
812 log("DcInactiveState nothandled msg.what=0x" +
813 Integer.toHexString(msg.what));
815 retVal = NOT_HANDLED;
821 private DcInactiveState mInactiveState = new DcInactiveState();
824 * The state machine is activating a connection.
826 private class DcActivatingState extends State {
828 public boolean processMessage(Message msg) {
834 case EVENT_DISCONNECT:
835 if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT"
842 if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = "
848 case EVENT_SETUP_DATA_CONNECTION_DONE:
849 if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
851 ar = (AsyncResult) msg.obj;
852 cp = (ConnectionParams) ar.userObj;
854 DataCallState.SetupResult result = onSetupConnectionCompleted(ar);
855 if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result);
859 mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
860 transitionTo(mActiveState);
863 // Vendor ril rejected the command and didn't connect.
864 // Transition to inactive but send notifications after
865 // we've entered the mInactive state.
866 mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);
867 transitionTo(mInactiveState);
869 case ERR_UnacceptableParameter:
870 // The addresses given from the RIL are bad
872 transitionTo(mDisconnectingErrorCreatingConnection);
874 case ERR_GetLastErrorFromRil:
875 // Request failed and this is an old RIL
876 phone.mCM.getLastDataCallFailCause(
877 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
880 // Request failed and mFailCause has the reason
881 mInactiveState.setEnterNotificationParams(cp, result.mFailCause,
882 getSuggestedRetryTime(ar));
883 transitionTo(mInactiveState);
886 // Request is stale, ignore.
889 throw new RuntimeException("Unknown SetupResult, should not happen");
894 case EVENT_GET_LAST_FAIL_DONE:
895 ar = (AsyncResult) msg.obj;
896 cp = (ConnectionParams) ar.userObj;
897 FailCause cause = FailCause.UNKNOWN;
899 if (cp.tag == mTag) {
900 if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");
901 if (ar.exception == null) {
902 int rilFailCause = ((int[]) (ar.result))[0];
903 cause = FailCause.fromInt(rilFailCause);
905 // Transition to inactive but send notifications after
906 // we've entered the mInactive state.
907 mInactiveState.setEnterNotificationParams(cp, cause, -1);
908 transitionTo(mInactiveState);
911 log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
912 + cp.tag + ", mTag=" + mTag);
921 log("DcActivatingState not handled msg.what=0x" +
922 Integer.toHexString(msg.what));
924 retVal = NOT_HANDLED;
930 private DcActivatingState mActivatingState = new DcActivatingState();
933 * The state machine is connected, expecting an EVENT_DISCONNECT.
935 private class DcActiveState extends State {
936 private ConnectionParams mConnectionParams = null;
937 private FailCause mFailCause = null;
939 public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) {
940 if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause");
941 mConnectionParams = cp;
945 @Override public void enter() {
947 * Now that we've transitioned to Active state we
948 * can send notifications. Previously we sent the
949 * notifications in the processMessage handler but
950 * that caused a race condition because the synchronous
953 if ((mConnectionParams != null) && (mFailCause != null)) {
954 if (VDBG) log("DcActiveState: enter notifyConnectCompleted");
955 notifyConnectCompleted(mConnectionParams, mFailCause);
961 // clear notifications
962 mConnectionParams = null;
967 public boolean processMessage(Message msg) {
973 if (DBG) log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mRefCount);
974 if (msg.obj != null) {
975 notifyConnectCompleted((ConnectionParams) msg.obj, FailCause.NONE);
979 case EVENT_DISCONNECT:
981 if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + mRefCount);
984 DisconnectParams dp = (DisconnectParams) msg.obj;
987 transitionTo(mDisconnectingState);
989 if (msg.obj != null) {
990 notifyDisconnectCompleted((DisconnectParams) msg.obj);
998 log("DcActiveState not handled msg.what=0x" +
999 Integer.toHexString(msg.what));
1001 retVal = NOT_HANDLED;
1007 private DcActiveState mActiveState = new DcActiveState();
1010 * The state machine is disconnecting.
1012 private class DcDisconnectingState extends State {
1014 public boolean processMessage(Message msg) {
1019 if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = "
1025 case EVENT_DEACTIVATE_DONE:
1026 if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
1027 AsyncResult ar = (AsyncResult) msg.obj;
1028 DisconnectParams dp = (DisconnectParams) ar.userObj;
1029 if (dp.tag == mTag) {
1030 // Transition to inactive but send notifications after
1031 // we've entered the mInactive state.
1032 mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj);
1033 transitionTo(mInactiveState);
1035 if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
1036 + dp.tag + " mTag=" + mTag);
1043 log("DcDisconnectingState not handled msg.what=0x" +
1044 Integer.toHexString(msg.what));
1046 retVal = NOT_HANDLED;
1052 private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
1055 * The state machine is disconnecting after an creating a connection.
1057 private class DcDisconnectionErrorCreatingConnection extends State {
1059 public boolean processMessage(Message msg) {
1063 case EVENT_DEACTIVATE_DONE:
1064 AsyncResult ar = (AsyncResult) msg.obj;
1065 ConnectionParams cp = (ConnectionParams) ar.userObj;
1066 if (cp.tag == mTag) {
1068 log("DcDisconnectionErrorCreatingConnection" +
1069 " msg.what=EVENT_DEACTIVATE_DONE");
1072 // Transition to inactive but send notifications after
1073 // we've entered the mInactive state.
1074 mInactiveState.setEnterNotificationParams(cp,
1075 FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1);
1076 transitionTo(mInactiveState);
1079 log("DcDisconnectionErrorCreatingConnection EVENT_DEACTIVATE_DONE" +
1080 " stale dp.tag=" + cp.tag + ", mTag=" + mTag);
1088 log("DcDisconnectionErrorCreatingConnection not handled msg.what=0x"
1089 + Integer.toHexString(msg.what));
1091 retVal = NOT_HANDLED;
1097 private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection =
1098 new DcDisconnectionErrorCreatingConnection();
1100 // ******* public interface
1103 * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
1104 * Used for cellular networks that use Acesss Point Names (APN) such
1107 * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
1108 * With AsyncResult.userObj set to the original msg.obj,
1109 * AsyncResult.result = FailCause and AsyncResult.exception = Exception().
1110 * @param apn is the Access Point Name to bring up a connection to
1112 public void bringUp(Message onCompletedMsg, ApnSetting apn) {
1113 sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
1117 * Tear down the connection through the apn on the network.
1119 * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
1120 * With AsyncResult.userObj set to the original msg.obj.
1122 public void tearDown(String reason, Message onCompletedMsg) {
1123 sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));