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; 18 19 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; 25 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; 34 import android.util.TimeUtils; 35 36 import java.io.FileDescriptor; 37 import java.io.PrintWriter; 38 import java.util.ArrayList; 39 import java.util.Calendar; 40 import java.util.HashMap; 41 import java.util.List; 42 43 /** 44 * {@hide} 45 * 46 * DataConnection StateMachine. 47 * 48 * This is an abstract base class for representing a single data connection. 49 * Instances of this class such as <code>CdmaDataConnection</code> and 50 * <code>GsmDataConnection</code>, * represent a connection via the cellular network. 51 * There may be multiple data connections and all of them are managed by the 52 * <code>DataConnectionTracker</code>. 53 * 54 * Instances are asynchronous state machines and have two primary entry points 55 * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned 56 * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult 57 * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful 58 * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>. 59 * If an error <code>AsyncResult.result = FailCause</code> and 60 * <code>AsyncResult.exception = new Exception()</code>. 61 * 62 * The other public methods are provided for debugging. 63 */ 64 public abstract class DataConnection extends StateMachine { 65 protected static final boolean DBG = true; 66 protected static final boolean VDBG = false; 67 68 protected static Object mCountLock = new Object(); 69 protected static int mCount; 70 protected AsyncChannel mAc; 71 72 protected List<ApnContext> mApnList = null; 73 PendingIntent mReconnectIntent = null; 74 75 private DataConnectionTracker mDataConnectionTracker = null; 76 77 /** 78 * Used internally for saving connecting parameters. 79 */ 80 protected static class ConnectionParams { 81 public ConnectionParams(ApnSetting apn, Message onCompletedMsg) { 82 this.apn = apn; 83 this.onCompletedMsg = onCompletedMsg; 84 } 85 86 public int tag; 87 public ApnSetting apn; 88 public Message onCompletedMsg; 89 } 90 91 /** 92 * Used internally for saving disconnecting parameters. 93 */ 94 protected static class DisconnectParams { 95 public DisconnectParams(String reason, Message onCompletedMsg) { 96 this.reason = reason; 97 this.onCompletedMsg = onCompletedMsg; 98 } 99 public int tag; 100 public String reason; 101 public Message onCompletedMsg; 102 } 103 104 /** 105 * Returned as the reason for a connection failure as defined 106 * by RIL_DataCallFailCause in ril.h and some local errors. 107 */ 108 public enum FailCause { 109 NONE(0), 110 111 // This series of errors as specified by the standards 112 // specified in ril.h 113 OPERATOR_BARRED(0x08), 114 INSUFFICIENT_RESOURCES(0x1A), 115 MISSING_UNKNOWN_APN(0x1B), 116 UNKNOWN_PDP_ADDRESS_TYPE(0x1C), 117 USER_AUTHENTICATION(0x1D), 118 ACTIVATION_REJECT_GGSN(0x1E), 119 ACTIVATION_REJECT_UNSPECIFIED(0x1F), 120 SERVICE_OPTION_NOT_SUPPORTED(0x20), 121 SERVICE_OPTION_NOT_SUBSCRIBED(0x21), 122 SERVICE_OPTION_OUT_OF_ORDER(0x22), 123 NSAPI_IN_USE(0x23), 124 ONLY_IPV4_ALLOWED(0x32), 125 ONLY_IPV6_ALLOWED(0x33), 126 ONLY_SINGLE_BEARER_ALLOWED(0x34), 127 PROTOCOL_ERRORS(0x6F), 128 129 // Local errors generated by Vendor RIL 130 // specified in ril.h 131 REGISTRATION_FAIL(-1), 132 GPRS_REGISTRATION_FAIL(-2), 133 SIGNAL_LOST(-3), 134 PREF_RADIO_TECH_CHANGED(-4), 135 RADIO_POWER_OFF(-5), 136 TETHERED_CALL_ACTIVE(-6), 137 ERROR_UNSPECIFIED(0xFFFF), 138 139 // Errors generated by the Framework 140 // specified here 141 UNKNOWN(0x10000), 142 RADIO_NOT_AVAILABLE(0x10001), 143 UNACCEPTABLE_NETWORK_PARAMETER(0x10002), 144 CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003); 145 146 private final int mErrorCode; 147 private static final HashMap<Integer, FailCause> sErrorCodeToFailCauseMap; 148 static { 149 sErrorCodeToFailCauseMap = new HashMap<Integer, FailCause>(); 150 for (FailCause fc : values()) { 151 sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc); 152 } 153 } 154 155 FailCause(int errorCode) { 156 mErrorCode = errorCode; 157 } 158 159 int getErrorCode() { 160 return mErrorCode; 161 } 162 163 public boolean isPermanentFail() { 164 return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) || 165 (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) || 166 (this == SERVICE_OPTION_NOT_SUPPORTED) || 167 (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) || 168 (this == PROTOCOL_ERRORS); 169 } 170 171 public boolean isEventLoggable() { 172 return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) || 173 (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) || 174 (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) || 175 (this == SERVICE_OPTION_NOT_SUBSCRIBED) || 176 (this == SERVICE_OPTION_NOT_SUPPORTED) || 177 (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) || 178 (this == PROTOCOL_ERRORS) || 179 (this == UNACCEPTABLE_NETWORK_PARAMETER); 180 } 181 182 public static FailCause fromInt(int errorCode) { 183 FailCause fc = sErrorCodeToFailCauseMap.get(errorCode); 184 if (fc == null) { 185 fc = UNKNOWN; 186 } 187 return fc; 188 } 189 } 190 191 public static class CallSetupException extends Exception { 192 private int mRetryOverride = -1; 193 194 CallSetupException (int retryOverride) { 195 mRetryOverride = retryOverride; 196 } 197 198 public int getRetryOverride() { 199 return mRetryOverride; 200 } 201 } 202 203 // ***** Event codes for driving the state machine 204 protected static final int BASE = Protocol.BASE_DATA_CONNECTION; 205 protected static final int EVENT_CONNECT = BASE + 0; 206 protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1; 207 protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2; 208 protected static final int EVENT_DEACTIVATE_DONE = BASE + 3; 209 protected static final int EVENT_DISCONNECT = BASE + 4; 210 protected static final int EVENT_RIL_CONNECTED = BASE + 5; 211 protected static final int EVENT_DISCONNECT_ALL = BASE + 6; 212 213 private static final int CMD_TO_STRING_COUNT = EVENT_DISCONNECT_ALL - BASE + 1; 214 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; 215 static { 216 sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; 217 sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] = 218 "EVENT_SETUP_DATA_CONNECTION_DONE"; 219 sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE"; 220 sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE"; 221 sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT"; 222 sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED"; 223 sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL"; 224 } 225 protected static String cmdToString(int cmd) { 226 cmd -= BASE; 227 if ((cmd >= 0) && (cmd < sCmdToString.length)) { 228 return sCmdToString[cmd]; 229 } else { 230 return null; 231 } 232 } 233 234 //***** Tag IDs for EventLog 235 protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; 236 237 //***** Member Variables 238 protected ApnSetting mApn; 239 protected int mTag; 240 protected PhoneBase phone; 241 protected int mRilVersion = -1; 242 protected int cid; 243 protected LinkProperties mLinkProperties = new LinkProperties(); 244 protected LinkCapabilities mCapabilities = new LinkCapabilities(); 245 protected long createTime; 246 protected long lastFailTime; 247 protected FailCause lastFailCause; 248 protected int mRetryOverride = -1; 249 protected static final String NULL_IP = "0.0.0.0"; 250 protected int mRefCount; 251 Object userData; 252 253 //***** Abstract methods 254 @Override 255 public abstract String toString(); 256 257 protected abstract void onConnect(ConnectionParams cp); 258 259 protected abstract boolean isDnsOk(String[] domainNameServers); 260 261 protected abstract void log(String s); 262 263 264 //***** Constructor 265 protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm, 266 DataConnectionTracker dct) { 267 super(name); 268 setProcessedMessagesSize(100); 269 if (DBG) log("DataConnection constructor E"); 270 this.phone = phone; 271 this.mDataConnectionTracker = dct; 272 mId = id; 273 mRetryMgr = rm; 274 this.cid = -1; 275 276 setDbg(false); 277 addState(mDefaultState); 278 addState(mInactiveState, mDefaultState); 279 addState(mActivatingState, mDefaultState); 280 addState(mActiveState, mDefaultState); 281 addState(mDisconnectingState, mDefaultState); 282 addState(mDisconnectingErrorCreatingConnection, mDefaultState); 283 setInitialState(mInactiveState); 284 285 mApnList = new ArrayList<ApnContext>(); 286 if (DBG) log("DataConnection constructor X"); 287 } 288 289 /** 290 * TearDown the data connection. 291 * 292 * @param o will be returned in AsyncResult.userObj 293 * and is either a DisconnectParams or ConnectionParams. 294 */ 295 private void tearDownData(Object o) { 296 int discReason = RILConstants.DEACTIVATE_REASON_NONE; 297 if ((o != null) && (o instanceof DisconnectParams)) { 298 DisconnectParams dp = (DisconnectParams)o; 299 Message m = dp.onCompletedMsg; 300 if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) { 301 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF; 302 } else if (TextUtils.equals(dp.reason, Phone.REASON_PDP_RESET)) { 303 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET; 304 } 305 } 306 if (phone.mCM.getRadioState().isOn()) { 307 if (DBG) log("tearDownData radio is on, call deactivateDataCall"); 308 phone.mCM.deactivateDataCall(cid, discReason, obtainMessage(EVENT_DEACTIVATE_DONE, o)); 309 } else { 310 if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately"); 311 AsyncResult ar = new AsyncResult(o, null, null); 312 sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar)); 313 } 314 } 315 316 /** 317 * Send the connectionCompletedMsg. 318 * 319 * @param cp is the ConnectionParams 320 * @param cause 321 */ 322 private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) { 323 Message connectionCompletedMsg = cp.onCompletedMsg; 324 if (connectionCompletedMsg == null) { 325 return; 326 } 327 328 long timeStamp = System.currentTimeMillis(); 329 connectionCompletedMsg.arg1 = cid; 330 331 if (cause == FailCause.NONE) { 332 createTime = timeStamp; 333 AsyncResult.forMessage(connectionCompletedMsg); 334 } else { 335 lastFailCause = cause; 336 lastFailTime = timeStamp; 337 AsyncResult.forMessage(connectionCompletedMsg, cause, 338 new CallSetupException(mRetryOverride)); 339 } 340 if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause); 341 342 connectionCompletedMsg.sendToTarget(); 343 } 344 345 /** 346 * Send ar.userObj if its a message, which is should be back to originator. 347 * 348 * @param dp is the DisconnectParams. 349 */ 350 private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { 351 if (VDBG) log("NotifyDisconnectCompleted"); 352 353 ApnContext alreadySent = null; 354 String reason = null; 355 356 if (dp.onCompletedMsg != null) { 357 // Get ApnContext, but only valid on GSM devices this is a string on CDMA devices. 358 Message msg = dp.onCompletedMsg; 359 if (msg.obj instanceof ApnContext) { 360 alreadySent = (ApnContext)msg.obj; 361 } 362 reason = dp.reason; 363 if (VDBG) { 364 log(String.format("msg=%s msg.obj=%s", msg.toString(), 365 ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); 366 } 367 AsyncResult.forMessage(msg); 368 msg.sendToTarget(); 369 } 370 if (sendAll) { 371 for (ApnContext a : mApnList) { 372 if (a == alreadySent) continue; 373 if (reason != null) a.setReason(reason); 374 Message msg = mDataConnectionTracker.obtainMessage( 375 DataConnectionTracker.EVENT_DISCONNECT_DONE, a); 376 AsyncResult.forMessage(msg); 377 msg.sendToTarget(); 378 } 379 } 380 381 if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); 382 } 383 384 protected int getRilRadioTechnology(int defaultRilRadioTechnology) { 385 int rilRadioTechnology; 386 if (mRilVersion < 6) { 387 rilRadioTechnology = defaultRilRadioTechnology; 388 } else { 389 rilRadioTechnology = phone.getServiceState().getRilRadioTechnology() + 2; 390 } 391 return rilRadioTechnology; 392 } 393 394 /* 395 * ************************************************************************** 396 * Begin Members and methods owned by DataConnectionTracker but stored 397 * in a DataConnection because there is one per connection. 398 * ************************************************************************** 399 */ 400 401 /* 402 * The id is owned by DataConnectionTracker. 403 */ 404 private int mId; 405 406 /** 407 * Get the DataConnection ID 408 */ 409 public int getDataConnectionId() { 410 return mId; 411 } 412 413 /* 414 * The retry manager is currently owned by the DataConnectionTracker but is stored 415 * in the DataConnection because there is one per connection. These methods 416 * should only be used by the DataConnectionTracker although someday the retrying 417 * maybe managed by the DataConnection itself and these methods could disappear. 418 */ 419 private RetryManager mRetryMgr; 420 421 /** 422 * @return retry manager retryCount 423 */ 424 public int getRetryCount() { 425 return mRetryMgr.getRetryCount(); 426 } 427 428 /** 429 * @return retry manager retryTimer 430 */ 431 public int getRetryTimer() { 432 return mRetryMgr.getRetryTimer(); 433 } 434 435 /** 436 * increaseRetryCount of retry manager 437 */ 438 public void increaseRetryCount() { 439 mRetryMgr.increaseRetryCount(); 440 } 441 442 /** 443 * @return retry manager isRetryNeeded 444 */ 445 public boolean isRetryNeeded() { 446 return mRetryMgr.isRetryNeeded(); 447 } 448 449 /** 450 * resetRetryCount of retry manager 451 */ 452 public void resetRetryCount() { 453 mRetryMgr.resetRetryCount(); 454 } 455 456 /** 457 * set retryForeverUsingLasttimeout of retry manager 458 */ 459 public void retryForeverUsingLastTimeout() { 460 mRetryMgr.retryForeverUsingLastTimeout(); 461 } 462 463 /** 464 * @return retry manager isRetryForever 465 */ 466 public boolean isRetryForever() { 467 return mRetryMgr.isRetryForever(); 468 } 469 470 /** 471 * @return whether the retry config is set successfully or not 472 */ 473 public boolean configureRetry(int maxRetryCount, int retryTime, int randomizationTime) { 474 return mRetryMgr.configure(maxRetryCount, retryTime, randomizationTime); 475 } 476 477 /** 478 * @return whether the retry config is set successfully or not 479 */ 480 public boolean configureRetry(String configStr) { 481 return mRetryMgr.configure(configStr); 482 } 483 484 /* 485 * ************************************************************************** 486 * End members owned by DataConnectionTracker 487 * ************************************************************************** 488 */ 489 490 /** 491 * Clear all settings called when entering mInactiveState. 492 */ 493 protected void clearSettings() { 494 if (DBG) log("clearSettings"); 495 496 createTime = -1; 497 lastFailTime = -1; 498 lastFailCause = FailCause.NONE; 499 mRetryOverride = -1; 500 mRefCount = 0; 501 cid = -1; 502 503 mLinkProperties = new LinkProperties(); 504 mApn = null; 505 } 506 507 /** 508 * Process setup completion. 509 * 510 * @param ar is the result 511 * @return SetupResult. 512 */ 513 private DataCallState.SetupResult onSetupConnectionCompleted(AsyncResult ar) { 514 DataCallState response = (DataCallState) ar.result; 515 ConnectionParams cp = (ConnectionParams) ar.userObj; 516 DataCallState.SetupResult result; 517 518 if (ar.exception != null) { 519 if (DBG) { 520 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception + 521 " response=" + response); 522 } 523 524 if (ar.exception instanceof CommandException 525 && ((CommandException) (ar.exception)).getCommandError() 526 == CommandException.Error.RADIO_NOT_AVAILABLE) { 527 result = DataCallState.SetupResult.ERR_BadCommand; 528 result.mFailCause = FailCause.RADIO_NOT_AVAILABLE; 529 } else if ((response == null) || (response.version < 4)) { 530 result = DataCallState.SetupResult.ERR_GetLastErrorFromRil; 531 } else { 532 result = DataCallState.SetupResult.ERR_RilError; 533 result.mFailCause = FailCause.fromInt(response.status); 534 } 535 } else if (cp.tag != mTag) { 536 if (DBG) { 537 log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag); 538 } 539 result = DataCallState.SetupResult.ERR_Stale; 540 } else if (response.status != 0) { 541 result = DataCallState.SetupResult.ERR_RilError; 542 result.mFailCause = FailCause.fromInt(response.status); 543 } else { 544 if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response); 545 cid = response.cid; 546 result = updateLinkProperty(response).setupResult; 547 } 548 549 return result; 550 } 551 552 private int getSuggestedRetryTime(AsyncResult ar) { 553 int retry = -1; 554 if (ar.exception == null) { 555 DataCallState response = (DataCallState) ar.result; 556 retry = response.suggestedRetryTime; 557 } 558 return retry; 559 } 560 561 private DataCallState.SetupResult setLinkProperties(DataCallState response, 562 LinkProperties lp) { 563 // Check if system property dns usable 564 boolean okToUseSystemPropertyDns = false; 565 String propertyPrefix = "net." + response.ifname + "."; 566 String dnsServers[] = new String[2]; 567 dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); 568 dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); 569 okToUseSystemPropertyDns = isDnsOk(dnsServers); 570 571 // set link properties based on data call response 572 return response.setLinkProperties(lp, okToUseSystemPropertyDns); 573 } 574 575 public static class UpdateLinkPropertyResult { 576 public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS; 577 public LinkProperties oldLp; 578 public LinkProperties newLp; 579 public UpdateLinkPropertyResult(LinkProperties curLp) { 580 oldLp = curLp; 581 newLp = curLp; 582 } 583 } 584 585 private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) { 586 UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties); 587 588 if (newState == null) return result; 589 590 DataCallState.SetupResult setupResult; 591 result.newLp = new LinkProperties(); 592 593 // set link properties based on data call response 594 result.setupResult = setLinkProperties(newState, result.newLp); 595 if (result.setupResult != DataCallState.SetupResult.SUCCESS) { 596 if (DBG) log("updateLinkProperty failed : " + result.setupResult); 597 return result; 598 } 599 // copy HTTP proxy as it is not part DataCallState. 600 result.newLp.setHttpProxy(mLinkProperties.getHttpProxy()); 601 602 if (DBG && (! result.oldLp.equals(result.newLp))) { 603 log("updateLinkProperty old LP=" + result.oldLp); 604 log("updateLinkProperty new LP=" + result.newLp); 605 } 606 mLinkProperties = result.newLp; 607 608 return result; 609 } 610 611 /** 612 * The parent state for all other states. 613 */ 614 private class DcDefaultState extends State { 615 @Override 616 public void enter() { 617 phone.mCM.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null); 618 } 619 @Override 620 public void exit() { 621 phone.mCM.unregisterForRilConnected(getHandler()); 622 } 623 @Override 624 public boolean processMessage(Message msg) { 625 AsyncResult ar; 626 627 switch (msg.what) { 628 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 629 if (mAc != null) { 630 if (VDBG) log("Disconnecting to previous connection mAc=" + mAc); 631 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 632 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED); 633 } else { 634 mAc = new AsyncChannel(); 635 mAc.connected(null, getHandler(), msg.replyTo); 636 if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected"); 637 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 638 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi"); 639 } 640 break; 641 } 642 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 643 if (VDBG) log("CMD_CHANNEL_DISCONNECT"); 644 mAc.disconnect(); 645 break; 646 } 647 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 648 if (VDBG) log("CMD_CHANNEL_DISCONNECTED"); 649 mAc = null; 650 break; 651 } 652 case DataConnectionAc.REQ_IS_INACTIVE: { 653 boolean val = getCurrentState() == mInactiveState; 654 if (VDBG) log("REQ_IS_INACTIVE isInactive=" + val); 655 mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0); 656 break; 657 } 658 case DataConnectionAc.REQ_GET_CID: { 659 if (VDBG) log("REQ_GET_CID cid=" + cid); 660 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid); 661 break; 662 } 663 case DataConnectionAc.REQ_GET_APNSETTING: { 664 if (VDBG) log("REQ_GET_APNSETTING apnSetting=" + mApn); 665 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn); 666 break; 667 } 668 case DataConnectionAc.REQ_GET_LINK_PROPERTIES: { 669 LinkProperties lp = new LinkProperties(mLinkProperties); 670 if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp); 671 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp); 672 break; 673 } 674 case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: { 675 ProxyProperties proxy = (ProxyProperties) msg.obj; 676 if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy); 677 mLinkProperties.setHttpProxy(proxy); 678 mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY); 679 break; 680 } 681 case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: { 682 DataCallState newState = (DataCallState) msg.obj; 683 UpdateLinkPropertyResult result = 684 updateLinkProperty(newState); 685 if (VDBG) { 686 log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result=" 687 + result + " newState=" + newState); 688 } 689 mAc.replyToMessage(msg, 690 DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, 691 result); 692 break; 693 } 694 case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: { 695 LinkCapabilities lc = new LinkCapabilities(mCapabilities); 696 if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc); 697 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc); 698 break; 699 } 700 case DataConnectionAc.REQ_RESET: 701 if (VDBG) log("DcDefaultState: msg.what=REQ_RESET"); 702 mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET); 703 transitionTo(mInactiveState); 704 break; 705 case DataConnectionAc.REQ_GET_REFCOUNT: { 706 if (VDBG) log("REQ_GET_REFCOUNT refCount=" + mRefCount); 707 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_REFCOUNT, mRefCount); 708 break; 709 } 710 case DataConnectionAc.REQ_ADD_APNCONTEXT: { 711 ApnContext apnContext = (ApnContext) msg.obj; 712 if (VDBG) log("REQ_ADD_APNCONTEXT apn=" + apnContext.getApnType()); 713 if (!mApnList.contains(apnContext)) { 714 mApnList.add(apnContext); 715 } 716 mAc.replyToMessage(msg, DataConnectionAc.RSP_ADD_APNCONTEXT); 717 break; 718 } 719 case DataConnectionAc.REQ_REMOVE_APNCONTEXT: { 720 ApnContext apnContext = (ApnContext) msg.obj; 721 if (VDBG) log("REQ_REMOVE_APNCONTEXT apn=" + apnContext.getApnType()); 722 mApnList.remove(apnContext); 723 mAc.replyToMessage(msg, DataConnectionAc.RSP_REMOVE_APNCONTEXT); 724 break; 725 } 726 case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: { 727 if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size()); 728 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST, 729 new ArrayList<ApnContext>(mApnList)); 730 break; 731 } 732 case DataConnectionAc.REQ_SET_RECONNECT_INTENT: { 733 PendingIntent intent = (PendingIntent) msg.obj; 734 if (VDBG) log("REQ_SET_RECONNECT_INTENT"); 735 mReconnectIntent = intent; 736 mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_RECONNECT_INTENT); 737 break; 738 } 739 case DataConnectionAc.REQ_GET_RECONNECT_INTENT: { 740 if (VDBG) log("REQ_GET_RECONNECT_INTENT"); 741 mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_RECONNECT_INTENT, 742 mReconnectIntent); 743 break; 744 } 745 case EVENT_CONNECT: 746 if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); 747 ConnectionParams cp = (ConnectionParams) msg.obj; 748 notifyConnectCompleted(cp, FailCause.UNKNOWN); 749 break; 750 751 case EVENT_DISCONNECT: 752 if (DBG) { 753 log("DcDefaultState deferring msg.what=EVENT_DISCONNECT" + mRefCount); 754 } 755 deferMessage(msg); 756 break; 757 758 case EVENT_DISCONNECT_ALL: 759 if (DBG) { 760 log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL" + mRefCount); 761 } 762 deferMessage(msg); 763 break; 764 765 case EVENT_RIL_CONNECTED: 766 ar = (AsyncResult)msg.obj; 767 if (ar.exception == null) { 768 mRilVersion = (Integer)ar.result; 769 if (DBG) { 770 log("DcDefaultState: msg.what=EVENT_RIL_CONNECTED mRilVersion=" + 771 mRilVersion); 772 } 773 } else { 774 log("Unexpected exception on EVENT_RIL_CONNECTED"); 775 mRilVersion = -1; 776 } 777 break; 778 779 default: 780 if (DBG) { 781 log("DcDefaultState: shouldn't happen but ignore msg.what=0x" + 782 Integer.toHexString(msg.what)); 783 } 784 break; 785 } 786 787 return HANDLED; 788 } 789 } 790 private DcDefaultState mDefaultState = new DcDefaultState(); 791 792 /** 793 * The state machine is inactive and expects a EVENT_CONNECT. 794 */ 795 private class DcInactiveState extends State { 796 private ConnectionParams mConnectionParams = null; 797 private FailCause mFailCause = null; 798 private DisconnectParams mDisconnectParams = null; 799 800 public void setEnterNotificationParams(ConnectionParams cp, FailCause cause, 801 int retryOverride) { 802 if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause"); 803 mConnectionParams = cp; 804 mFailCause = cause; 805 mRetryOverride = retryOverride; 806 } 807 808 public void setEnterNotificationParams(DisconnectParams dp) { 809 if (VDBG) log("DcInactiveState: setEnterNoticationParams dp"); 810 mDisconnectParams = dp; 811 } 812 813 @Override 814 public void enter() { 815 mTag += 1; 816 817 /** 818 * Now that we've transitioned to Inactive state we 819 * can send notifications. Previously we sent the 820 * notifications in the processMessage handler but 821 * that caused a race condition because the synchronous 822 * call to isInactive. 823 */ 824 if ((mConnectionParams != null) && (mFailCause != null)) { 825 if (VDBG) log("DcInactiveState: enter notifyConnectCompleted"); 826 notifyConnectCompleted(mConnectionParams, mFailCause); 827 } 828 if (mDisconnectParams != null) { 829 if (VDBG) log("DcInactiveState: enter notifyDisconnectCompleted"); 830 notifyDisconnectCompleted(mDisconnectParams, true); 831 } 832 clearSettings(); 833 } 834 835 @Override 836 public void exit() { 837 // clear notifications 838 mConnectionParams = null; 839 mFailCause = null; 840 mDisconnectParams = null; 841 } 842 843 @Override 844 public boolean processMessage(Message msg) { 845 boolean retVal; 846 847 switch (msg.what) { 848 case DataConnectionAc.REQ_RESET: 849 if (DBG) { 850 log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset"); 851 } 852 mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET); 853 retVal = HANDLED; 854 break; 855 856 case EVENT_CONNECT: 857 ConnectionParams cp = (ConnectionParams) msg.obj; 858 cp.tag = mTag; 859 if (DBG) { 860 log("DcInactiveState msg.what=EVENT_CONNECT." + "RefCount = " 861 + mRefCount); 862 } 863 mRefCount = 1; 864 onConnect(cp); 865 transitionTo(mActivatingState); 866 retVal = HANDLED; 867 break; 868 869 case EVENT_DISCONNECT: 870 if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); 871 notifyDisconnectCompleted((DisconnectParams)msg.obj, false); 872 retVal = HANDLED; 873 break; 874 875 case EVENT_DISCONNECT_ALL: 876 if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); 877 notifyDisconnectCompleted((DisconnectParams)msg.obj, false); 878 retVal = HANDLED; 879 break; 880 881 default: 882 if (VDBG) { 883 log("DcInactiveState nothandled msg.what=0x" + 884 Integer.toHexString(msg.what)); 885 } 886 retVal = NOT_HANDLED; 887 break; 888 } 889 return retVal; 890 } 891 } 892 private DcInactiveState mInactiveState = new DcInactiveState(); 893 894 /** 895 * The state machine is activating a connection. 896 */ 897 private class DcActivatingState extends State { 898 @Override 899 public boolean processMessage(Message msg) { 900 boolean retVal; 901 AsyncResult ar; 902 ConnectionParams cp; 903 904 switch (msg.what) { 905 case EVENT_CONNECT: 906 if (DBG) log("DcActivatingState deferring msg.what=EVENT_CONNECT refCount = " 907 + mRefCount); 908 deferMessage(msg); 909 retVal = HANDLED; 910 break; 911 912 case EVENT_SETUP_DATA_CONNECTION_DONE: 913 if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE"); 914 915 ar = (AsyncResult) msg.obj; 916 cp = (ConnectionParams) ar.userObj; 917 918 DataCallState.SetupResult result = onSetupConnectionCompleted(ar); 919 if (DBG) log("DcActivatingState onSetupConnectionCompleted result=" + result); 920 switch (result) { 921 case SUCCESS: 922 // All is well 923 mActiveState.setEnterNotificationParams(cp, FailCause.NONE); 924 transitionTo(mActiveState); 925 break; 926 case ERR_BadCommand: 927 // Vendor ril rejected the command and didn't connect. 928 // Transition to inactive but send notifications after 929 // we've entered the mInactive state. 930 mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1); 931 transitionTo(mInactiveState); 932 break; 933 case ERR_UnacceptableParameter: 934 // The addresses given from the RIL are bad 935 tearDownData(cp); 936 transitionTo(mDisconnectingErrorCreatingConnection); 937 break; 938 case ERR_GetLastErrorFromRil: 939 // Request failed and this is an old RIL 940 phone.mCM.getLastDataCallFailCause( 941 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp)); 942 break; 943 case ERR_RilError: 944 // Request failed and mFailCause has the reason 945 mInactiveState.setEnterNotificationParams(cp, result.mFailCause, 946 getSuggestedRetryTime(ar)); 947 transitionTo(mInactiveState); 948 break; 949 case ERR_Stale: 950 // Request is stale, ignore. 951 break; 952 default: 953 throw new RuntimeException("Unknown SetupResult, should not happen"); 954 } 955 retVal = HANDLED; 956 break; 957 958 case EVENT_GET_LAST_FAIL_DONE: 959 ar = (AsyncResult) msg.obj; 960 cp = (ConnectionParams) ar.userObj; 961 FailCause cause = FailCause.UNKNOWN; 962 963 if (cp.tag == mTag) { 964 if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"); 965 if (ar.exception == null) { 966 int rilFailCause = ((int[]) (ar.result))[0]; 967 cause = FailCause.fromInt(rilFailCause); 968 } 969 // Transition to inactive but send notifications after 970 // we've entered the mInactive state. 971 mInactiveState.setEnterNotificationParams(cp, cause, -1); 972 transitionTo(mInactiveState); 973 } else { 974 if (DBG) { 975 log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag=" 976 + cp.tag + ", mTag=" + mTag); 977 } 978 } 979 980 retVal = HANDLED; 981 break; 982 983 default: 984 if (VDBG) { 985 log("DcActivatingState not handled msg.what=0x" + 986 Integer.toHexString(msg.what)); 987 } 988 retVal = NOT_HANDLED; 989 break; 990 } 991 return retVal; 992 } 993 } 994 private DcActivatingState mActivatingState = new DcActivatingState(); 995 996 /** 997 * The state machine is connected, expecting an EVENT_DISCONNECT. 998 */ 999 private class DcActiveState extends State { 1000 private ConnectionParams mConnectionParams = null; 1001 private FailCause mFailCause = null; 1002 1003 public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) { 1004 if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause"); 1005 mConnectionParams = cp; 1006 mFailCause = cause; 1007 } 1008 1009 @Override public void enter() { 1010 /** 1011 * Now that we've transitioned to Active state we 1012 * can send notifications. Previously we sent the 1013 * notifications in the processMessage handler but 1014 * that caused a race condition because the synchronous 1015 * call to isActive. 1016 */ 1017 if ((mConnectionParams != null) && (mFailCause != null)) { 1018 if (VDBG) log("DcActiveState: enter notifyConnectCompleted"); 1019 notifyConnectCompleted(mConnectionParams, mFailCause); 1020 } 1021 } 1022 1023 @Override 1024 public void exit() { 1025 // clear notifications 1026 mConnectionParams = null; 1027 mFailCause = null; 1028 } 1029 1030 @Override 1031 public boolean processMessage(Message msg) { 1032 boolean retVal; 1033 1034 switch (msg.what) { 1035 case EVENT_CONNECT: 1036 mRefCount++; 1037 if (DBG) log("DcActiveState msg.what=EVENT_CONNECT RefCount=" + mRefCount); 1038 if (msg.obj != null) { 1039 notifyConnectCompleted((ConnectionParams) msg.obj, FailCause.NONE); 1040 } 1041 retVal = HANDLED; 1042 break; 1043 case EVENT_DISCONNECT: 1044 mRefCount--; 1045 if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + mRefCount); 1046 if (mRefCount == 0) 1047 { 1048 DisconnectParams dp = (DisconnectParams) msg.obj; 1049 dp.tag = mTag; 1050 tearDownData(dp); 1051 transitionTo(mDisconnectingState); 1052 } else { 1053 if (msg.obj != null) { 1054 notifyDisconnectCompleted((DisconnectParams) msg.obj, false); 1055 } 1056 } 1057 retVal = HANDLED; 1058 break; 1059 1060 case EVENT_DISCONNECT_ALL: 1061 if (DBG) { 1062 log("DcActiveState msg.what=EVENT_DISCONNECT_ALL RefCount=" + mRefCount); 1063 } 1064 mRefCount = 0; 1065 DisconnectParams dp = (DisconnectParams) msg.obj; 1066 dp.tag = mTag; 1067 tearDownData(dp); 1068 transitionTo(mDisconnectingState); 1069 retVal = HANDLED; 1070 break; 1071 1072 default: 1073 if (VDBG) { 1074 log("DcActiveState not handled msg.what=0x" + 1075 Integer.toHexString(msg.what)); 1076 } 1077 retVal = NOT_HANDLED; 1078 break; 1079 } 1080 return retVal; 1081 } 1082 } 1083 private DcActiveState mActiveState = new DcActiveState(); 1084 1085 /** 1086 * The state machine is disconnecting. 1087 */ 1088 private class DcDisconnectingState extends State { 1089 @Override 1090 public boolean processMessage(Message msg) { 1091 boolean retVal; 1092 1093 switch (msg.what) { 1094 case EVENT_CONNECT: 1095 if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " 1096 + mRefCount); 1097 deferMessage(msg); 1098 retVal = HANDLED; 1099 break; 1100 1101 case EVENT_DEACTIVATE_DONE: 1102 if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE"); 1103 AsyncResult ar = (AsyncResult) msg.obj; 1104 DisconnectParams dp = (DisconnectParams) ar.userObj; 1105 if (dp.tag == mTag) { 1106 // Transition to inactive but send notifications after 1107 // we've entered the mInactive state. 1108 mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj); 1109 transitionTo(mInactiveState); 1110 } else { 1111 if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag=" 1112 + dp.tag + " mTag=" + mTag); 1113 } 1114 retVal = HANDLED; 1115 break; 1116 1117 default: 1118 if (VDBG) { 1119 log("DcDisconnectingState not handled msg.what=0x" + 1120 Integer.toHexString(msg.what)); 1121 } 1122 retVal = NOT_HANDLED; 1123 break; 1124 } 1125 return retVal; 1126 } 1127 } 1128 private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); 1129 1130 /** 1131 * The state machine is disconnecting after an creating a connection. 1132 */ 1133 private class DcDisconnectionErrorCreatingConnection extends State { 1134 @Override 1135 public boolean processMessage(Message msg) { 1136 boolean retVal; 1137 1138 switch (msg.what) { 1139 case EVENT_DEACTIVATE_DONE: 1140 AsyncResult ar = (AsyncResult) msg.obj; 1141 ConnectionParams cp = (ConnectionParams) ar.userObj; 1142 if (cp.tag == mTag) { 1143 if (DBG) { 1144 log("DcDisconnectionErrorCreatingConnection" + 1145 " msg.what=EVENT_DEACTIVATE_DONE"); 1146 } 1147 1148 // Transition to inactive but send notifications after 1149 // we've entered the mInactive state. 1150 mInactiveState.setEnterNotificationParams(cp, 1151 FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1); 1152 transitionTo(mInactiveState); 1153 } else { 1154 if (DBG) { 1155 log("DcDisconnectionErrorCreatingConnection EVENT_DEACTIVATE_DONE" + 1156 " stale dp.tag=" + cp.tag + ", mTag=" + mTag); 1157 } 1158 } 1159 retVal = HANDLED; 1160 break; 1161 1162 default: 1163 if (VDBG) { 1164 log("DcDisconnectionErrorCreatingConnection not handled msg.what=0x" 1165 + Integer.toHexString(msg.what)); 1166 } 1167 retVal = NOT_HANDLED; 1168 break; 1169 } 1170 return retVal; 1171 } 1172 } 1173 private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = 1174 new DcDisconnectionErrorCreatingConnection(); 1175 1176 // ******* public interface 1177 1178 /** 1179 * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg. 1180 * Used for cellular networks that use Acesss Point Names (APN) such 1181 * as GSM networks. 1182 * 1183 * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. 1184 * With AsyncResult.userObj set to the original msg.obj, 1185 * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). 1186 * @param apn is the Access Point Name to bring up a connection to 1187 */ 1188 public void bringUp(Message onCompletedMsg, ApnSetting apn) { 1189 sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg))); 1190 } 1191 1192 /** 1193 * Tear down the connection through the apn on the network. 1194 * 1195 * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. 1196 * With AsyncResult.userObj set to the original msg.obj. 1197 */ 1198 public void tearDown(String reason, Message onCompletedMsg) { 1199 sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg))); 1200 } 1201 1202 /** 1203 * Tear down the connection through the apn on the network. Ignores refcount and 1204 * and always tears down. 1205 * 1206 * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. 1207 * With AsyncResult.userObj set to the original msg.obj. 1208 */ 1209 public void tearDownAll(String reason, Message onCompletedMsg) { 1210 sendMessage(obtainMessage(EVENT_DISCONNECT_ALL, 1211 new DisconnectParams(reason, onCompletedMsg))); 1212 } 1213 1214 /** 1215 * @return the string for msg.what as our info. 1216 */ 1217 @Override 1218 protected String getMessageInfo(Message msg) { 1219 String info = null; 1220 info = cmdToString(msg.what); 1221 if (info == null) { 1222 info = DataConnectionAc.cmdToString(msg.what); 1223 } 1224 return info; 1225 } 1226 1227 /** 1228 * Dump the current state. 1229 * 1230 * @param fd 1231 * @param pw 1232 * @param args 1233 */ 1234 @Override 1235 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1236 pw.print("DataConnection "); 1237 super.dump(fd, pw, args); 1238 pw.println(" mApnList=" + mApnList); 1239 pw.flush(); 1240 pw.println(" mDataConnectionTracker=" + mDataConnectionTracker); 1241 pw.println(" mApn=" + mApn); 1242 pw.println(" mTag=" + mTag); 1243 pw.flush(); 1244 pw.println(" phone=" + phone); 1245 pw.println(" mRilVersion=" + mRilVersion); 1246 pw.println(" cid=" + cid); 1247 pw.flush(); 1248 pw.println(" mLinkProperties=" + mLinkProperties); 1249 pw.flush(); 1250 pw.println(" mCapabilities=" + mCapabilities); 1251 pw.println(" createTime=" + TimeUtils.logTimeOfDay(createTime)); 1252 pw.println(" lastFailTime=" + TimeUtils.logTimeOfDay(lastFailTime)); 1253 pw.println(" lastFailCause=" + lastFailCause); 1254 pw.flush(); 1255 pw.println(" mRetryOverride=" + mRetryOverride); 1256 pw.println(" mRefCount=" + mRefCount); 1257 pw.println(" userData=" + userData); 1258 if (mRetryMgr != null) pw.println(" " + mRetryMgr); 1259 pw.flush(); 1260 } 1261 } 1262