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