1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.dataconnection; 18 19 20 import com.android.internal.telephony.CommandException; 21 import com.android.internal.telephony.DctConstants; 22 import com.android.internal.telephony.Phone; 23 import com.android.internal.telephony.PhoneBase; 24 import com.android.internal.telephony.PhoneConstants; 25 import com.android.internal.telephony.RILConstants; 26 import com.android.internal.telephony.RetryManager; 27 import com.android.internal.util.AsyncChannel; 28 import com.android.internal.util.Protocol; 29 import com.android.internal.util.State; 30 import com.android.internal.util.StateMachine; 31 32 import android.app.PendingIntent; 33 import android.net.LinkCapabilities; 34 import android.net.LinkProperties; 35 import android.net.ProxyProperties; 36 import android.os.AsyncResult; 37 import android.os.Build; 38 import android.os.Message; 39 import android.os.SystemClock; 40 import android.os.SystemProperties; 41 import android.telephony.Rlog; 42 import android.telephony.ServiceState; 43 import android.telephony.TelephonyManager; 44 import android.text.TextUtils; 45 import android.util.Pair; 46 import android.util.Patterns; 47 import android.util.TimeUtils; 48 49 import java.io.FileDescriptor; 50 import java.io.PrintWriter; 51 import java.util.ArrayList; 52 import java.util.List; 53 import java.util.concurrent.atomic.AtomicInteger; 54 55 /** 56 * {@hide} 57 * 58 * DataConnection StateMachine. 59 * 60 * This a class for representing a single data connection, with instances of this 61 * class representing a connection via the cellular network. There may be multiple 62 * data connections and all of them are managed by the <code>DataConnectionTracker</code>. 63 * 64 * A recent change is to move retry handling into this class, with that change the 65 * old retry manager is now used internally rather than exposed to the DCT. Also, 66 * bringUp now has an initialRetry which is used limit the number of retries 67 * during the initial bring up of the connection. After the connection becomes active 68 * the current max retry is restored to the configured value. 69 * 70 * NOTE: All DataConnection objects must be running on the same looper, which is the default 71 * as the coordinator has members which are used without synchronization. 72 */ 73 public final class DataConnection extends StateMachine { 74 private static final boolean DBG = true; 75 private static final boolean VDBG = true; 76 77 /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ 78 private static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," 79 + "5000,10000,20000,40000,80000:5000,160000:5000," 80 + "320000:5000,640000:5000,1280000:5000,1800000:5000"; 81 82 /** Retry configuration for secondary networks: 4 tries in 20 sec */ 83 private static final String SECONDARY_DATA_RETRY_CONFIG = 84 "max_retries=3, 5000, 5000, 5000"; 85 86 // The data connection controller 87 private DcController mDcController; 88 89 // The Tester for failing all bringup's 90 private DcTesterFailBringUpAll mDcTesterFailBringUpAll; 91 92 private static AtomicInteger mInstanceNumber = new AtomicInteger(0); 93 private AsyncChannel mAc; 94 95 // Utilities for the DataConnection 96 private DcRetryAlarmController mDcRetryAlarmController; 97 98 // The DCT that's talking to us, we only support one! 99 private DcTrackerBase mDct = null; 100 101 /** 102 * Used internally for saving connecting parameters. 103 */ 104 static class ConnectionParams { 105 int mTag; 106 ApnContext mApnContext; 107 int mInitialMaxRetry; 108 int mProfileId; 109 int mRilRat; 110 Message mOnCompletedMsg; 111 112 ConnectionParams(ApnContext apnContext, int initialMaxRetry, int profileId, 113 int rilRadioTechnology, Message onCompletedMsg) { 114 mApnContext = apnContext; 115 mInitialMaxRetry = initialMaxRetry; 116 mProfileId = profileId; 117 mRilRat = rilRadioTechnology; 118 mOnCompletedMsg = onCompletedMsg; 119 } 120 121 @Override 122 public String toString() { 123 return "{mTag=" + mTag + " mApnContext=" + mApnContext 124 + " mInitialMaxRetry=" + mInitialMaxRetry + " mProfileId=" + mProfileId 125 + " mRat=" + mRilRat 126 + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; 127 } 128 } 129 130 /** 131 * Used internally for saving disconnecting parameters. 132 */ 133 static class DisconnectParams { 134 int mTag; 135 ApnContext mApnContext; 136 String mReason; 137 Message mOnCompletedMsg; 138 139 DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) { 140 mApnContext = apnContext; 141 mReason = reason; 142 mOnCompletedMsg = onCompletedMsg; 143 } 144 145 @Override 146 public String toString() { 147 return "{mTag=" + mTag + " mApnContext=" + mApnContext 148 + " mReason=" + mReason 149 + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; 150 } 151 } 152 153 private ApnSetting mApnSetting; 154 private ConnectionParams mConnectionParams; 155 private DisconnectParams mDisconnectParams; 156 private DcFailCause mDcFailCause; 157 158 private PhoneBase mPhone; 159 private LinkProperties mLinkProperties = new LinkProperties(); 160 private LinkCapabilities mLinkCapabilities = new LinkCapabilities(); 161 private long mCreateTime; 162 private long mLastFailTime; 163 private DcFailCause mLastFailCause; 164 private static final String NULL_IP = "0.0.0.0"; 165 private Object mUserData; 166 private int mRilRat = Integer.MAX_VALUE; 167 private int mDataRegState = Integer.MAX_VALUE; 168 169 //***** Package visible variables 170 int mTag; 171 int mCid; 172 List<ApnContext> mApnContexts = null; 173 PendingIntent mReconnectIntent = null; 174 RetryManager mRetryManager = new RetryManager(); 175 176 177 // ***** Event codes for driving the state machine, package visible for Dcc 178 static final int BASE = Protocol.BASE_DATA_CONNECTION; 179 static final int EVENT_CONNECT = BASE + 0; 180 static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1; 181 static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2; 182 static final int EVENT_DEACTIVATE_DONE = BASE + 3; 183 static final int EVENT_DISCONNECT = BASE + 4; 184 static final int EVENT_RIL_CONNECTED = BASE + 5; 185 static final int EVENT_DISCONNECT_ALL = BASE + 6; 186 static final int EVENT_DATA_STATE_CHANGED = BASE + 7; 187 static final int EVENT_TEAR_DOWN_NOW = BASE + 8; 188 static final int EVENT_LOST_CONNECTION = BASE + 9; 189 static final int EVENT_RETRY_CONNECTION = BASE + 10; 190 static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11; 191 192 private static final int CMD_TO_STRING_COUNT = EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE + 1; 193 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; 194 static { 195 sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; 196 sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] = 197 "EVENT_SETUP_DATA_CONNECTION_DONE"; 198 sCmdToString[EVENT_GET_LAST_FAIL_DONE - BASE] = "EVENT_GET_LAST_FAIL_DONE"; 199 sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE"; 200 sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT"; 201 sCmdToString[EVENT_RIL_CONNECTED - BASE] = "EVENT_RIL_CONNECTED"; 202 sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL"; 203 sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED"; 204 sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW"; 205 sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION"; 206 sCmdToString[EVENT_RETRY_CONNECTION - BASE] = "EVENT_RETRY_CONNECTION"; 207 sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] = 208 "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"; 209 } 210 // Convert cmd to string or null if unknown 211 static String cmdToString(int cmd) { 212 String value; 213 cmd -= BASE; 214 if ((cmd >= 0) && (cmd < sCmdToString.length)) { 215 value = sCmdToString[cmd]; 216 } else { 217 value = DcAsyncChannel.cmdToString(cmd + BASE); 218 } 219 if (value == null) { 220 value = "0x" + Integer.toHexString(cmd + BASE); 221 } 222 return value; 223 } 224 225 /** 226 * Create the connection object 227 * 228 * @param phone the Phone 229 * @param id the connection id 230 * @return DataConnection that was created. 231 */ 232 static DataConnection makeDataConnection(PhoneBase phone, int id, 233 DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll, 234 DcController dcc) { 235 DataConnection dc = new DataConnection(phone, 236 "DC-" + mInstanceNumber.incrementAndGet(), id, dct, failBringUpAll, dcc); 237 dc.start(); 238 if (DBG) dc.log("Made " + dc.getName()); 239 return dc; 240 } 241 242 void dispose() { 243 log("dispose: call quiteNow()"); 244 quitNow(); 245 } 246 247 /* Getter functions */ 248 249 LinkCapabilities getCopyLinkCapabilities() { 250 return new LinkCapabilities(mLinkCapabilities); 251 } 252 253 LinkProperties getCopyLinkProperties() { 254 return new LinkProperties(mLinkProperties); 255 } 256 257 boolean getIsInactive() { 258 return getCurrentState() == mInactiveState; 259 } 260 261 int getCid() { 262 return mCid; 263 } 264 265 ApnSetting getApnSetting() { 266 return mApnSetting; 267 } 268 269 void setLinkPropertiesHttpProxy(ProxyProperties proxy) { 270 mLinkProperties.setHttpProxy(proxy); 271 } 272 273 static class UpdateLinkPropertyResult { 274 public DataCallResponse.SetupResult setupResult = DataCallResponse.SetupResult.SUCCESS; 275 public LinkProperties oldLp; 276 public LinkProperties newLp; 277 public UpdateLinkPropertyResult(LinkProperties curLp) { 278 oldLp = curLp; 279 newLp = curLp; 280 } 281 } 282 283 UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) { 284 UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties); 285 286 if (newState == null) return result; 287 288 DataCallResponse.SetupResult setupResult; 289 result.newLp = new LinkProperties(); 290 291 // set link properties based on data call response 292 result.setupResult = setLinkProperties(newState, result.newLp); 293 if (result.setupResult != DataCallResponse.SetupResult.SUCCESS) { 294 if (DBG) log("updateLinkProperty failed : " + result.setupResult); 295 return result; 296 } 297 // copy HTTP proxy as it is not part DataCallResponse. 298 result.newLp.setHttpProxy(mLinkProperties.getHttpProxy()); 299 300 if (DBG && (! result.oldLp.equals(result.newLp))) { 301 log("updateLinkProperty old LP=" + result.oldLp); 302 log("updateLinkProperty new LP=" + result.newLp); 303 } 304 mLinkProperties = result.newLp; 305 306 return result; 307 } 308 309 //***** Constructor (NOTE: uses dcc.getHandler() as its Handler) 310 private DataConnection(PhoneBase phone, String name, int id, 311 DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll, 312 DcController dcc) { 313 super(name, dcc.getHandler()); 314 setLogRecSize(300); 315 setLogOnlyTransitions(true); 316 if (DBG) log("DataConnection constructor E"); 317 318 mPhone = phone; 319 mDct = dct; 320 mDcTesterFailBringUpAll = failBringUpAll; 321 mDcController = dcc; 322 mId = id; 323 mCid = -1; 324 mDcRetryAlarmController = new DcRetryAlarmController(mPhone, this); 325 mRilRat = mPhone.getServiceState().getRilDataRadioTechnology(); 326 mDataRegState = mPhone.getServiceState().getDataRegState(); 327 328 addState(mDefaultState); 329 addState(mInactiveState, mDefaultState); 330 addState(mActivatingState, mDefaultState); 331 addState(mRetryingState, mDefaultState); 332 addState(mActiveState, mDefaultState); 333 addState(mDisconnectingState, mDefaultState); 334 addState(mDisconnectingErrorCreatingConnection, mDefaultState); 335 setInitialState(mInactiveState); 336 337 mApnContexts = new ArrayList<ApnContext>(); 338 if (DBG) log("DataConnection constructor X"); 339 } 340 341 private String getRetryConfig(boolean forDefault) { 342 int nt = mPhone.getServiceState().getNetworkType(); 343 344 if (Build.IS_DEBUGGABLE) { 345 String config = SystemProperties.get("test.data_retry_config"); 346 if (! TextUtils.isEmpty(config)) { 347 return config; 348 } 349 } 350 351 if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) || 352 (nt == TelephonyManager.NETWORK_TYPE_1xRTT) || 353 (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) || 354 (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) || 355 (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) || 356 (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) { 357 // CDMA variant 358 return SystemProperties.get("ro.cdma.data_retry_config"); 359 } else { 360 // Use GSM variant for all others. 361 if (forDefault) { 362 return SystemProperties.get("ro.gsm.data_retry_config"); 363 } else { 364 return SystemProperties.get("ro.gsm.2nd_data_retry_config"); 365 } 366 } 367 } 368 369 private void configureRetry(boolean forDefault) { 370 String retryConfig = getRetryConfig(forDefault); 371 372 if (!mRetryManager.configure(retryConfig)) { 373 if (forDefault) { 374 if (!mRetryManager.configure(DEFAULT_DATA_RETRY_CONFIG)) { 375 // Should never happen, log an error and default to a simple linear sequence. 376 loge("configureRetry: Could not configure using " + 377 "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG); 378 mRetryManager.configure(5, 2000, 1000); 379 } 380 } else { 381 if (!mRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) { 382 // Should never happen, log an error and default to a simple sequence. 383 loge("configureRetry: Could note configure using " + 384 "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG); 385 mRetryManager.configure(5, 2000, 1000); 386 } 387 } 388 } 389 if (DBG) { 390 log("configureRetry: forDefault=" + forDefault + " mRetryManager=" + mRetryManager); 391 } 392 } 393 394 /** 395 * Begin setting up a data connection, calls setupDataCall 396 * and the ConnectionParams will be returned with the 397 * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj. 398 * 399 * @param cp is the connection parameters 400 */ 401 private void onConnect(ConnectionParams cp) { 402 if (DBG) log("onConnect: carrier='" + mApnSetting.carrier 403 + "' APN='" + mApnSetting.apn 404 + "' proxy='" + mApnSetting.proxy + "' port='" + mApnSetting.port + "'"); 405 406 // Check if we should fake an error. 407 if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { 408 DataCallResponse response = new DataCallResponse(); 409 response.version = mPhone.mCi.getRilVersion(); 410 response.status = mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause.getErrorCode(); 411 response.cid = 0; 412 response.active = 0; 413 response.type = ""; 414 response.ifname = ""; 415 response.addresses = new String[0]; 416 response.dnses = new String[0]; 417 response.gateways = new String[0]; 418 response.suggestedRetryTime = 419 mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime; 420 421 Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); 422 AsyncResult.forMessage(msg, response, null); 423 sendMessage(msg); 424 if (DBG) { 425 log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() 426 + " send error response=" + response); 427 } 428 mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; 429 return; 430 } 431 432 mCreateTime = -1; 433 mLastFailTime = -1; 434 mLastFailCause = DcFailCause.NONE; 435 436 // msg.obj will be returned in AsyncResult.userObj; 437 Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); 438 msg.obj = cp; 439 440 int authType = mApnSetting.authType; 441 if (authType == -1) { 442 authType = TextUtils.isEmpty(mApnSetting.user) ? RILConstants.SETUP_DATA_AUTH_NONE 443 : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; 444 } 445 446 String protocol; 447 if (mPhone.getServiceState().getRoaming()) { 448 protocol = mApnSetting.roamingProtocol; 449 } else { 450 protocol = mApnSetting.protocol; 451 } 452 453 mPhone.mCi.setupDataCall( 454 Integer.toString(cp.mRilRat + 2), 455 Integer.toString(cp.mProfileId), 456 mApnSetting.apn, mApnSetting.user, mApnSetting.password, 457 Integer.toString(authType), 458 protocol, msg); 459 } 460 461 /** 462 * TearDown the data connection when the deactivation is complete a Message with 463 * msg.what == EVENT_DEACTIVATE_DONE and msg.obj == AsyncResult with AsyncResult.obj 464 * containing the parameter o. 465 * 466 * @param o is the object returned in the AsyncResult.obj. 467 */ 468 private void tearDownData(Object o) { 469 int discReason = RILConstants.DEACTIVATE_REASON_NONE; 470 if ((o != null) && (o instanceof DisconnectParams)) { 471 DisconnectParams dp = (DisconnectParams)o; 472 473 if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)) { 474 discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF; 475 } else if (TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { 476 discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET; 477 } 478 } 479 if (mPhone.mCi.getRadioState().isOn()) { 480 if (DBG) log("tearDownData radio is on, call deactivateDataCall"); 481 mPhone.mCi.deactivateDataCall(mCid, discReason, 482 obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o)); 483 } else { 484 if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately"); 485 AsyncResult ar = new AsyncResult(o, null, null); 486 sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar)); 487 } 488 } 489 490 private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) { 491 for (ApnContext apnContext : mApnContexts) { 492 if (apnContext == alreadySent) continue; 493 if (reason != null) apnContext.setReason(reason); 494 Message msg = mDct.obtainMessage(event, apnContext); 495 AsyncResult.forMessage(msg); 496 msg.sendToTarget(); 497 } 498 } 499 500 private void notifyAllOfConnected(String reason) { 501 notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason); 502 } 503 504 private void notifyAllOfDisconnectDcRetrying(String reason) { 505 notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DC_RETRYING, reason); 506 } 507 private void notifyAllDisconnectCompleted(DcFailCause cause) { 508 notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, cause.toString()); 509 } 510 511 512 /** 513 * Send the connectionCompletedMsg. 514 * 515 * @param cp is the ConnectionParams 516 * @param cause and if no error the cause is DcFailCause.NONE 517 * @param sendAll is true if all contexts are to be notified 518 */ 519 private void notifyConnectCompleted(ConnectionParams cp, DcFailCause cause, boolean sendAll) { 520 ApnContext alreadySent = null; 521 522 if (cp != null && cp.mOnCompletedMsg != null) { 523 // Get the completed message but only use it once 524 Message connectionCompletedMsg = cp.mOnCompletedMsg; 525 cp.mOnCompletedMsg = null; 526 if (connectionCompletedMsg.obj instanceof ApnContext) { 527 alreadySent = (ApnContext)connectionCompletedMsg.obj; 528 } 529 530 long timeStamp = System.currentTimeMillis(); 531 connectionCompletedMsg.arg1 = mCid; 532 533 if (cause == DcFailCause.NONE) { 534 mCreateTime = timeStamp; 535 AsyncResult.forMessage(connectionCompletedMsg); 536 } else { 537 mLastFailCause = cause; 538 mLastFailTime = timeStamp; 539 540 // Return message with a Throwable exception to signify an error. 541 if (cause == null) cause = DcFailCause.UNKNOWN; 542 AsyncResult.forMessage(connectionCompletedMsg, cause, 543 new Throwable(cause.toString())); 544 } 545 if (DBG) { 546 log("notifyConnectCompleted at " + timeStamp + " cause=" + cause 547 + " connectionCompletedMsg=" + msgToString(connectionCompletedMsg)); 548 } 549 550 connectionCompletedMsg.sendToTarget(); 551 } 552 if (sendAll) { 553 notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR, 554 cause.toString()); 555 } 556 } 557 558 /** 559 * Send ar.userObj if its a message, which is should be back to originator. 560 * 561 * @param dp is the DisconnectParams. 562 */ 563 private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { 564 if (VDBG) log("NotifyDisconnectCompleted"); 565 566 ApnContext alreadySent = null; 567 String reason = null; 568 569 if (dp != null && dp.mOnCompletedMsg != null) { 570 // Get the completed message but only use it once 571 Message msg = dp.mOnCompletedMsg; 572 dp.mOnCompletedMsg = null; 573 if (msg.obj instanceof ApnContext) { 574 alreadySent = (ApnContext)msg.obj; 575 } 576 reason = dp.mReason; 577 if (VDBG) { 578 log(String.format("msg=%s msg.obj=%s", msg.toString(), 579 ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); 580 } 581 AsyncResult.forMessage(msg); 582 msg.sendToTarget(); 583 } 584 if (sendAll) { 585 if (reason == null) { 586 reason = DcFailCause.UNKNOWN.toString(); 587 } 588 notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason); 589 } 590 if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); 591 } 592 593 /* 594 * ************************************************************************** 595 * Begin Members and methods owned by DataConnectionTracker but stored 596 * in a DataConnection because there is one per connection. 597 * ************************************************************************** 598 */ 599 600 /* 601 * The id is owned by DataConnectionTracker. 602 */ 603 private int mId; 604 605 /** 606 * Get the DataConnection ID 607 */ 608 public int getDataConnectionId() { 609 return mId; 610 } 611 612 /* 613 * ************************************************************************** 614 * End members owned by DataConnectionTracker 615 * ************************************************************************** 616 */ 617 618 /** 619 * Clear all settings called when entering mInactiveState. 620 */ 621 private void clearSettings() { 622 if (DBG) log("clearSettings"); 623 624 mCreateTime = -1; 625 mLastFailTime = -1; 626 mLastFailCause = DcFailCause.NONE; 627 mCid = -1; 628 629 mLinkProperties = new LinkProperties(); 630 mApnContexts.clear(); 631 mApnSetting = null; 632 mDcFailCause = null; 633 } 634 635 /** 636 * Process setup completion. 637 * 638 * @param ar is the result 639 * @return SetupResult. 640 */ 641 private DataCallResponse.SetupResult onSetupConnectionCompleted(AsyncResult ar) { 642 DataCallResponse response = (DataCallResponse) ar.result; 643 ConnectionParams cp = (ConnectionParams) ar.userObj; 644 DataCallResponse.SetupResult result; 645 646 if (cp.mTag != mTag) { 647 if (DBG) { 648 log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); 649 } 650 result = DataCallResponse.SetupResult.ERR_Stale; 651 } else if (ar.exception != null) { 652 if (DBG) { 653 log("onSetupConnectionCompleted failed, ar.exception=" + ar.exception + 654 " response=" + response); 655 } 656 657 if (ar.exception instanceof CommandException 658 && ((CommandException) (ar.exception)).getCommandError() 659 == CommandException.Error.RADIO_NOT_AVAILABLE) { 660 result = DataCallResponse.SetupResult.ERR_BadCommand; 661 result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE; 662 } else if ((response == null) || (response.version < 4)) { 663 result = DataCallResponse.SetupResult.ERR_GetLastErrorFromRil; 664 } else { 665 result = DataCallResponse.SetupResult.ERR_RilError; 666 result.mFailCause = DcFailCause.fromInt(response.status); 667 } 668 } else if (response.status != 0) { 669 result = DataCallResponse.SetupResult.ERR_RilError; 670 result.mFailCause = DcFailCause.fromInt(response.status); 671 } else { 672 if (DBG) log("onSetupConnectionCompleted received DataCallResponse: " + response); 673 mCid = response.cid; 674 result = updateLinkProperty(response).setupResult; 675 } 676 677 return result; 678 } 679 680 private boolean isDnsOk(String[] domainNameServers) { 681 if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1]) 682 && !mPhone.isDnsCheckDisabled()) { 683 // Work around a race condition where QMI does not fill in DNS: 684 // Deactivate PDP and let DataConnectionTracker retry. 685 // Do not apply the race condition workaround for MMS APN 686 // if Proxy is an IP-address. 687 // Otherwise, the default APN will not be restored anymore. 688 if (!mApnSetting.types[0].equals(PhoneConstants.APN_TYPE_MMS) 689 || !isIpAddress(mApnSetting.mmsProxy)) { 690 log(String.format( 691 "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s", 692 mApnSetting.types[0], PhoneConstants.APN_TYPE_MMS, mApnSetting.mmsProxy, 693 isIpAddress(mApnSetting.mmsProxy))); 694 return false; 695 } 696 } 697 return true; 698 } 699 700 private boolean isIpAddress(String address) { 701 if (address == null) return false; 702 703 return Patterns.IP_ADDRESS.matcher(address).matches(); 704 } 705 706 private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response, 707 LinkProperties lp) { 708 // Check if system property dns usable 709 boolean okToUseSystemPropertyDns = false; 710 String propertyPrefix = "net." + response.ifname + "."; 711 String dnsServers[] = new String[2]; 712 dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); 713 dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); 714 okToUseSystemPropertyDns = isDnsOk(dnsServers); 715 716 // set link properties based on data call response 717 return response.setLinkProperties(lp, okToUseSystemPropertyDns); 718 } 719 720 /** 721 * Initialize connection, this will fail if the 722 * apnSettings are not compatible. 723 * 724 * @param cp the Connection paramemters 725 * @return true if initialization was successful. 726 */ 727 private boolean initConnection(ConnectionParams cp) { 728 ApnContext apnContext = cp.mApnContext; 729 if (mApnSetting == null) { 730 // Only change apn setting if it isn't set, it will 731 // only NOT be set only if we're in DcInactiveState. 732 mApnSetting = apnContext.getApnSetting(); 733 } else if (mApnSetting.canHandleType(apnContext.getApnType())) { 734 // All is good. 735 } else { 736 if (DBG) { 737 log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp 738 + " dc=" + DataConnection.this); 739 } 740 return false; 741 } 742 mTag += 1; 743 mConnectionParams = cp; 744 mConnectionParams.mTag = mTag; 745 746 if (!mApnContexts.contains(apnContext)) { 747 mApnContexts.add(apnContext); 748 } 749 configureRetry(mApnSetting.canHandleType(PhoneConstants.APN_TYPE_DEFAULT)); 750 mRetryManager.setRetryCount(0); 751 mRetryManager.setCurMaxRetryCount(mConnectionParams.mInitialMaxRetry); 752 mRetryManager.setRetryForever(false); 753 754 if (DBG) { 755 log("initConnection: " 756 + " RefCount=" + mApnContexts.size() 757 + " mApnList=" + mApnContexts 758 + " mConnectionParams=" + mConnectionParams); 759 } 760 return true; 761 } 762 763 /** 764 * The parent state for all other states. 765 */ 766 private class DcDefaultState extends State { 767 @Override 768 public void enter() { 769 if (DBG) log("DcDefaultState: enter"); 770 771 // Register for DRS or RAT change 772 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(), 773 DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null); 774 775 // Add ourselves to the list of data connections 776 mDcController.addDc(DataConnection.this); 777 } 778 @Override 779 public void exit() { 780 if (DBG) log("DcDefaultState: exit"); 781 782 // Unregister for DRS or RAT change. 783 mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler()); 784 785 // Remove ourselves from the DC lists 786 mDcController.removeDc(DataConnection.this); 787 788 if (mAc != null) { 789 mAc.disconnected(); 790 mAc = null; 791 } 792 mDcRetryAlarmController.dispose(); 793 mDcRetryAlarmController = null; 794 mApnContexts = null; 795 mReconnectIntent = null; 796 mDct = null; 797 mApnSetting = null; 798 mPhone = null; 799 mLinkProperties = null; 800 mLinkCapabilities = null; 801 mLastFailCause = null; 802 mUserData = null; 803 mDcController = null; 804 mDcTesterFailBringUpAll = null; 805 } 806 807 @Override 808 public boolean processMessage(Message msg) { 809 boolean retVal = HANDLED; 810 811 if (VDBG) { 812 log("DcDefault msg=" + getWhatToString(msg.what) 813 + " RefCount=" + mApnContexts.size()); 814 } 815 switch (msg.what) { 816 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 817 if (mAc != null) { 818 if (VDBG) log("Disconnecting to previous connection mAc=" + mAc); 819 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 820 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED); 821 } else { 822 mAc = new AsyncChannel(); 823 mAc.connected(null, getHandler(), msg.replyTo); 824 if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected"); 825 mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 826 AsyncChannel.STATUS_SUCCESSFUL, mId, "hi"); 827 } 828 break; 829 } 830 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 831 if (VDBG) log("CMD_CHANNEL_DISCONNECTED"); 832 quit(); 833 break; 834 } 835 case DcAsyncChannel.REQ_IS_INACTIVE: { 836 boolean val = getIsInactive(); 837 if (VDBG) log("REQ_IS_INACTIVE isInactive=" + val); 838 mAc.replyToMessage(msg, DcAsyncChannel.RSP_IS_INACTIVE, val ? 1 : 0); 839 break; 840 } 841 case DcAsyncChannel.REQ_GET_CID: { 842 int cid = getCid(); 843 if (VDBG) log("REQ_GET_CID cid=" + cid); 844 mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_CID, cid); 845 break; 846 } 847 case DcAsyncChannel.REQ_GET_APNSETTING: { 848 ApnSetting apnSetting = getApnSetting(); 849 if (VDBG) log("REQ_GET_APNSETTING mApnSetting=" + apnSetting); 850 mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_APNSETTING, apnSetting); 851 break; 852 } 853 case DcAsyncChannel.REQ_GET_LINK_PROPERTIES: { 854 LinkProperties lp = getCopyLinkProperties(); 855 if (VDBG) log("REQ_GET_LINK_PROPERTIES linkProperties" + lp); 856 mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_PROPERTIES, lp); 857 break; 858 } 859 case DcAsyncChannel.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: { 860 ProxyProperties proxy = (ProxyProperties) msg.obj; 861 if (VDBG) log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy); 862 setLinkPropertiesHttpProxy(proxy); 863 mAc.replyToMessage(msg, DcAsyncChannel.RSP_SET_LINK_PROPERTIES_HTTP_PROXY); 864 break; 865 } 866 case DcAsyncChannel.REQ_GET_LINK_CAPABILITIES: { 867 LinkCapabilities lc = getCopyLinkCapabilities(); 868 if (VDBG) log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc); 869 mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_LINK_CAPABILITIES, lc); 870 break; 871 } 872 case DcAsyncChannel.REQ_RESET: 873 if (VDBG) log("DcDefaultState: msg.what=REQ_RESET"); 874 transitionTo(mInactiveState); 875 break; 876 case EVENT_CONNECT: 877 if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); 878 ConnectionParams cp = (ConnectionParams) msg.obj; 879 notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false); 880 break; 881 882 case EVENT_DISCONNECT: 883 if (DBG) { 884 log("DcDefaultState deferring msg.what=EVENT_DISCONNECT RefCount=" 885 + mApnContexts.size()); 886 } 887 deferMessage(msg); 888 break; 889 890 case EVENT_DISCONNECT_ALL: 891 if (DBG) { 892 log("DcDefaultState deferring msg.what=EVENT_DISCONNECT_ALL RefCount=" 893 + mApnContexts.size()); 894 } 895 deferMessage(msg); 896 break; 897 898 case EVENT_TEAR_DOWN_NOW: 899 if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW"); 900 mPhone.mCi.deactivateDataCall(mCid, 0, null); 901 break; 902 903 case EVENT_LOST_CONNECTION: 904 if (DBG) { 905 String s = "DcDefaultState ignore EVENT_LOST_CONNECTION" 906 + " tag=" + msg.arg1 + ":mTag=" + mTag; 907 logAndAddLogRec(s); 908 } 909 break; 910 911 case EVENT_RETRY_CONNECTION: 912 if (DBG) { 913 String s = "DcDefaultState ignore EVENT_RETRY_CONNECTION" 914 + " tag=" + msg.arg1 + ":mTag=" + mTag; 915 logAndAddLogRec(s); 916 } 917 break; 918 919 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: 920 AsyncResult ar = (AsyncResult)msg.obj; 921 Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result; 922 mDataRegState = drsRatPair.first; 923 mRilRat = drsRatPair.second; 924 if (DBG) { 925 log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" 926 + " drs=" + mDataRegState 927 + " mRilRat=" + mRilRat); 928 } 929 break; 930 931 default: 932 if (DBG) { 933 log("DcDefaultState: shouldn't happen but ignore msg.what=" 934 + getWhatToString(msg.what)); 935 } 936 break; 937 } 938 939 return retVal; 940 } 941 } 942 private DcDefaultState mDefaultState = new DcDefaultState(); 943 944 /** 945 * The state machine is inactive and expects a EVENT_CONNECT. 946 */ 947 private class DcInactiveState extends State { 948 // Inform all contexts we've failed connecting 949 public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) { 950 if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause"); 951 mConnectionParams = cp; 952 mDisconnectParams = null; 953 mDcFailCause = cause; 954 } 955 956 // Inform all contexts we've failed disconnected 957 public void setEnterNotificationParams(DisconnectParams dp) { 958 if (VDBG) log("DcInactiveState: setEnterNoticationParams dp"); 959 mConnectionParams = null; 960 mDisconnectParams = dp; 961 mDcFailCause = DcFailCause.NONE; 962 } 963 964 // Inform all contexts of the failure cause 965 public void setEnterNotificationParams(DcFailCause cause) { 966 mConnectionParams = null; 967 mDisconnectParams = null; 968 mDcFailCause = cause; 969 } 970 971 @Override 972 public void enter() { 973 mTag += 1; 974 if (DBG) log("DcInactiveState: enter() mTag=" + mTag); 975 976 if (mConnectionParams != null) { 977 if (DBG) { 978 log("DcInactiveState: enter notifyConnectCompleted +ALL failCause=" 979 + mDcFailCause); 980 } 981 notifyConnectCompleted(mConnectionParams, mDcFailCause, true); 982 } 983 if (mDisconnectParams != null) { 984 if (DBG) { 985 log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause=" 986 + mDcFailCause); 987 } 988 notifyDisconnectCompleted(mDisconnectParams, true); 989 } 990 if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) { 991 if (DBG) { 992 log("DcInactiveState: enter notifyAllDisconnectCompleted failCause=" 993 + mDcFailCause); 994 } 995 notifyAllDisconnectCompleted(mDcFailCause); 996 } 997 998 // Remove ourselves from cid mapping, before clearSettings 999 mDcController.removeActiveDcByCid(DataConnection.this); 1000 1001 clearSettings(); 1002 } 1003 1004 @Override 1005 public void exit() { 1006 } 1007 1008 @Override 1009 public boolean processMessage(Message msg) { 1010 boolean retVal; 1011 1012 switch (msg.what) { 1013 case DcAsyncChannel.REQ_RESET: 1014 if (DBG) { 1015 log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset"); 1016 } 1017 retVal = HANDLED; 1018 break; 1019 1020 case EVENT_CONNECT: 1021 if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); 1022 ConnectionParams cp = (ConnectionParams) msg.obj; 1023 if (initConnection(cp)) { 1024 onConnect(mConnectionParams); 1025 transitionTo(mActivatingState); 1026 } else { 1027 if (DBG) { 1028 log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); 1029 } 1030 notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER, 1031 false); 1032 } 1033 retVal = HANDLED; 1034 break; 1035 1036 case EVENT_DISCONNECT: 1037 if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); 1038 notifyDisconnectCompleted((DisconnectParams)msg.obj, false); 1039 retVal = HANDLED; 1040 break; 1041 1042 case EVENT_DISCONNECT_ALL: 1043 if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); 1044 notifyDisconnectCompleted((DisconnectParams)msg.obj, false); 1045 retVal = HANDLED; 1046 break; 1047 1048 default: 1049 if (VDBG) { 1050 log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what)); 1051 } 1052 retVal = NOT_HANDLED; 1053 break; 1054 } 1055 return retVal; 1056 } 1057 } 1058 private DcInactiveState mInactiveState = new DcInactiveState(); 1059 1060 /** 1061 * The state machine is retrying and expects a EVENT_RETRY_CONNECTION. 1062 */ 1063 private class DcRetryingState extends State { 1064 @Override 1065 public void enter() { 1066 if ((mConnectionParams.mRilRat != mRilRat) 1067 || (mDataRegState != ServiceState.STATE_IN_SERVICE)){ 1068 // RAT has changed or we're not in service so don't even begin retrying. 1069 if (DBG) { 1070 String s = "DcRetryingState: enter() not retrying rat changed" 1071 + ", mConnectionParams.mRilRat=" + mConnectionParams.mRilRat 1072 + " != mRilRat:" + mRilRat 1073 + " transitionTo(mInactiveState)"; 1074 logAndAddLogRec(s); 1075 } 1076 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION); 1077 transitionTo(mInactiveState); 1078 } else { 1079 if (DBG) { 1080 log("DcRetryingState: enter() mTag=" + mTag 1081 + ", call notifyAllOfDisconnectDcRetrying lostConnection"); 1082 } 1083 1084 notifyAllOfDisconnectDcRetrying(Phone.REASON_LOST_DATA_CONNECTION); 1085 1086 // Remove ourselves from cid mapping 1087 mDcController.removeActiveDcByCid(DataConnection.this); 1088 mCid = -1; 1089 } 1090 } 1091 1092 @Override 1093 public boolean processMessage(Message msg) { 1094 boolean retVal; 1095 1096 switch (msg.what) { 1097 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: 1098 AsyncResult ar = (AsyncResult)msg.obj; 1099 Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result; 1100 int drs = drsRatPair.first; 1101 int rat = drsRatPair.second; 1102 if ((rat == mRilRat) && (drs == mDataRegState)) { 1103 if (DBG) { 1104 log("DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" 1105 + " strange no change in drs=" + drs 1106 + " rat=" + rat + " ignoring"); 1107 } 1108 } else { 1109 // We've lost the connection and we're retrying but DRS or RAT changed 1110 // so we may never succeed, might as well give up. 1111 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION); 1112 deferMessage(msg); 1113 transitionTo(mInactiveState); 1114 1115 if (DBG) { 1116 String s = "DcRetryingState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" 1117 + " giving up changed from " + mRilRat 1118 + " to rat=" + rat 1119 + " or drs changed from " + mDataRegState + " to drs=" + drs; 1120 logAndAddLogRec(s); 1121 } 1122 mDataRegState = drs; 1123 mRilRat = rat; 1124 } 1125 retVal = HANDLED; 1126 break; 1127 1128 case EVENT_RETRY_CONNECTION: { 1129 if (msg.arg1 == mTag) { 1130 mRetryManager.increaseRetryCount(); 1131 if (DBG) { 1132 log("DcRetryingState EVENT_RETRY_CONNECTION" 1133 + " RetryCount=" + mRetryManager.getRetryCount() 1134 + " mConnectionParams=" + mConnectionParams); 1135 } 1136 onConnect(mConnectionParams); 1137 transitionTo(mActivatingState); 1138 } else { 1139 if (DBG) { 1140 log("DcRetryingState stale EVENT_RETRY_CONNECTION" 1141 + " tag:" + msg.arg1 + " != mTag:" + mTag); 1142 } 1143 } 1144 retVal = HANDLED; 1145 break; 1146 } 1147 case DcAsyncChannel.REQ_RESET: { 1148 if (DBG) { 1149 log("DcRetryingState: msg.what=RSP_RESET, ignore we're already reset"); 1150 } 1151 mInactiveState.setEnterNotificationParams(mConnectionParams, 1152 DcFailCause.RESET_BY_FRAMEWORK); 1153 transitionTo(mInactiveState); 1154 retVal = HANDLED; 1155 break; 1156 } 1157 case EVENT_CONNECT: { 1158 ConnectionParams cp = (ConnectionParams) msg.obj; 1159 if (DBG) { 1160 log("DcRetryingState: msg.what=EVENT_CONNECT" 1161 + " RefCount=" + mApnContexts.size() + " cp=" + cp 1162 + " mConnectionParams=" + mConnectionParams); 1163 } 1164 if (initConnection(cp)) { 1165 onConnect(mConnectionParams); 1166 transitionTo(mActivatingState); 1167 } else { 1168 if (DBG) { 1169 log("DcRetryingState: msg.what=EVENT_CONNECT initConnection failed"); 1170 } 1171 notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER, 1172 false); 1173 } 1174 retVal = HANDLED; 1175 break; 1176 } 1177 case EVENT_DISCONNECT: { 1178 DisconnectParams dp = (DisconnectParams) msg.obj; 1179 1180 if (mApnContexts.remove(dp.mApnContext) && mApnContexts.size() == 0) { 1181 if (DBG) { 1182 log("DcRetryingState msg.what=EVENT_DISCONNECT " + " RefCount=" 1183 + mApnContexts.size() + " dp=" + dp); 1184 } 1185 mInactiveState.setEnterNotificationParams(dp); 1186 transitionTo(mInactiveState); 1187 } else { 1188 if (DBG) log("DcRetryingState: msg.what=EVENT_DISCONNECT"); 1189 notifyDisconnectCompleted(dp, false); 1190 } 1191 retVal = HANDLED; 1192 break; 1193 } 1194 case EVENT_DISCONNECT_ALL: { 1195 if (DBG) { 1196 log("DcRetryingState msg.what=EVENT_DISCONNECT/DISCONNECT_ALL " 1197 + "RefCount=" + mApnContexts.size()); 1198 } 1199 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION); 1200 transitionTo(mInactiveState); 1201 retVal = HANDLED; 1202 break; 1203 } 1204 default: { 1205 if (VDBG) { 1206 log("DcRetryingState nothandled msg.what=" + getWhatToString(msg.what)); 1207 } 1208 retVal = NOT_HANDLED; 1209 break; 1210 } 1211 } 1212 return retVal; 1213 } 1214 } 1215 private DcRetryingState mRetryingState = new DcRetryingState(); 1216 1217 /** 1218 * The state machine is activating a connection. 1219 */ 1220 private class DcActivatingState extends State { 1221 @Override 1222 public boolean processMessage(Message msg) { 1223 boolean retVal; 1224 AsyncResult ar; 1225 ConnectionParams cp; 1226 1227 if (DBG) log("DcActivatingState: msg=" + msgToString(msg)); 1228 switch (msg.what) { 1229 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: 1230 case EVENT_CONNECT: 1231 // Activating can't process until we're done. 1232 deferMessage(msg); 1233 retVal = HANDLED; 1234 break; 1235 1236 case EVENT_SETUP_DATA_CONNECTION_DONE: 1237 ar = (AsyncResult) msg.obj; 1238 cp = (ConnectionParams) ar.userObj; 1239 1240 DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar); 1241 if (result != DataCallResponse.SetupResult.ERR_Stale) { 1242 if (mConnectionParams != cp) { 1243 loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams 1244 + " != cp:" + cp); 1245 } 1246 } 1247 if (DBG) { 1248 log("DcActivatingState onSetupConnectionCompleted result=" + result 1249 + " dc=" + DataConnection.this); 1250 } 1251 switch (result) { 1252 case SUCCESS: 1253 // All is well 1254 mDcFailCause = DcFailCause.NONE; 1255 transitionTo(mActiveState); 1256 break; 1257 case ERR_BadCommand: 1258 // Vendor ril rejected the command and didn't connect. 1259 // Transition to inactive but send notifications after 1260 // we've entered the mInactive state. 1261 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1262 transitionTo(mInactiveState); 1263 break; 1264 case ERR_UnacceptableParameter: 1265 // The addresses given from the RIL are bad 1266 tearDownData(cp); 1267 transitionTo(mDisconnectingErrorCreatingConnection); 1268 break; 1269 case ERR_GetLastErrorFromRil: 1270 // Request failed and this is an old RIL 1271 mPhone.mCi.getLastDataCallFailCause( 1272 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp)); 1273 break; 1274 case ERR_RilError: 1275 int delay = mDcRetryAlarmController.getSuggestedRetryTime( 1276 DataConnection.this, ar); 1277 if (DBG) { 1278 log("DcActivatingState: ERR_RilError " 1279 + " delay=" + delay 1280 + " isRetryNeeded=" + mRetryManager.isRetryNeeded() 1281 + " result=" + result 1282 + " result.isRestartRadioFail=" + 1283 result.mFailCause.isRestartRadioFail() 1284 + " result.isPermanentFail=" + 1285 result.mFailCause.isPermanentFail()); 1286 } 1287 if (result.mFailCause.isRestartRadioFail()) { 1288 if (DBG) log("DcActivatingState: ERR_RilError restart radio"); 1289 mDct.sendRestartRadio(); 1290 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1291 transitionTo(mInactiveState); 1292 } else if (result.mFailCause.isPermanentFail()) { 1293 if (DBG) log("DcActivatingState: ERR_RilError perm error"); 1294 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1295 transitionTo(mInactiveState); 1296 } else if (delay >= 0) { 1297 if (DBG) log("DcActivatingState: ERR_RilError retry"); 1298 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, 1299 mTag, delay); 1300 transitionTo(mRetryingState); 1301 } else { 1302 if (DBG) log("DcActivatingState: ERR_RilError no retry"); 1303 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1304 transitionTo(mInactiveState); 1305 } 1306 break; 1307 case ERR_Stale: 1308 loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE" 1309 + " tag:" + cp.mTag + " != mTag:" + mTag); 1310 break; 1311 default: 1312 throw new RuntimeException("Unknown SetupResult, should not happen"); 1313 } 1314 retVal = HANDLED; 1315 break; 1316 1317 case EVENT_GET_LAST_FAIL_DONE: 1318 ar = (AsyncResult) msg.obj; 1319 cp = (ConnectionParams) ar.userObj; 1320 if (cp.mTag == mTag) { 1321 if (mConnectionParams != cp) { 1322 loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams 1323 + " != cp:" + cp); 1324 } 1325 1326 DcFailCause cause = DcFailCause.UNKNOWN; 1327 1328 if (ar.exception == null) { 1329 int rilFailCause = ((int[]) (ar.result))[0]; 1330 cause = DcFailCause.fromInt(rilFailCause); 1331 if (cause == DcFailCause.NONE) { 1332 if (DBG) { 1333 log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE" 1334 + " BAD: error was NONE, change to UNKNOWN"); 1335 } 1336 cause = DcFailCause.UNKNOWN; 1337 } 1338 } 1339 mDcFailCause = cause; 1340 1341 int retryDelay = mRetryManager.getRetryTimer(); 1342 if (DBG) { 1343 log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE" 1344 + " cause=" + cause 1345 + " retryDelay=" + retryDelay 1346 + " isRetryNeeded=" + mRetryManager.isRetryNeeded() 1347 + " dc=" + DataConnection.this); 1348 } 1349 if (cause.isRestartRadioFail()) { 1350 if (DBG) { 1351 log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE" 1352 + " restart radio"); 1353 } 1354 mDct.sendRestartRadio(); 1355 mInactiveState.setEnterNotificationParams(cp, cause); 1356 transitionTo(mInactiveState); 1357 } else if (cause.isPermanentFail()) { 1358 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE perm er"); 1359 mInactiveState.setEnterNotificationParams(cp, cause); 1360 transitionTo(mInactiveState); 1361 } else if ((retryDelay >= 0) && (mRetryManager.isRetryNeeded())) { 1362 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE retry"); 1363 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag, 1364 retryDelay); 1365 transitionTo(mRetryingState); 1366 } else { 1367 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE no retry"); 1368 mInactiveState.setEnterNotificationParams(cp, cause); 1369 transitionTo(mInactiveState); 1370 } 1371 } else { 1372 loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE" 1373 + " tag:" + cp.mTag + " != mTag:" + mTag); 1374 } 1375 1376 retVal = HANDLED; 1377 break; 1378 1379 default: 1380 if (VDBG) { 1381 log("DcActivatingState not handled msg.what=" + 1382 getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); 1383 } 1384 retVal = NOT_HANDLED; 1385 break; 1386 } 1387 return retVal; 1388 } 1389 } 1390 private DcActivatingState mActivatingState = new DcActivatingState(); 1391 1392 /** 1393 * The state machine is connected, expecting an EVENT_DISCONNECT. 1394 */ 1395 private class DcActiveState extends State { 1396 @Override public void enter() { 1397 if (DBG) log("DcActiveState: enter dc=" + DataConnection.this); 1398 1399 if (mRetryManager.getRetryCount() != 0) { 1400 log("DcActiveState: connected after retrying call notifyAllOfConnected"); 1401 mRetryManager.setRetryCount(0); 1402 } 1403 // If we were retrying there maybe more than one, otherwise they'll only be one. 1404 notifyAllOfConnected(Phone.REASON_CONNECTED); 1405 1406 // If the EVENT_CONNECT set the current max retry restore it here 1407 // if it didn't then this is effectively a NOP. 1408 mRetryManager.restoreCurMaxRetryCount(); 1409 mDcController.addActiveDcByCid(DataConnection.this); 1410 } 1411 1412 @Override 1413 public void exit() { 1414 if (DBG) log("DcActiveState: exit dc=" + this); 1415 } 1416 1417 @Override 1418 public boolean processMessage(Message msg) { 1419 boolean retVal; 1420 1421 switch (msg.what) { 1422 case EVENT_CONNECT: { 1423 ConnectionParams cp = (ConnectionParams) msg.obj; 1424 if (DBG) { 1425 log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this); 1426 } 1427 if (mApnContexts.contains(cp.mApnContext)) { 1428 log("DcActiveState ERROR already added apnContext=" + cp.mApnContext); 1429 } else { 1430 mApnContexts.add(cp.mApnContext); 1431 if (DBG) { 1432 log("DcActiveState msg.what=EVENT_CONNECT RefCount=" 1433 + mApnContexts.size()); 1434 } 1435 } 1436 notifyConnectCompleted(cp, DcFailCause.NONE, false); 1437 retVal = HANDLED; 1438 break; 1439 } 1440 case EVENT_DISCONNECT: { 1441 DisconnectParams dp = (DisconnectParams) msg.obj; 1442 if (DBG) { 1443 log("DcActiveState: EVENT_DISCONNECT dp=" + dp 1444 + " dc=" + DataConnection.this); 1445 } 1446 if (mApnContexts.contains(dp.mApnContext)) { 1447 if (DBG) { 1448 log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" 1449 + mApnContexts.size()); 1450 } 1451 1452 if (mApnContexts.size() == 1) { 1453 mApnContexts.clear(); 1454 mDisconnectParams = dp; 1455 mConnectionParams = null; 1456 dp.mTag = mTag; 1457 tearDownData(dp); 1458 transitionTo(mDisconnectingState); 1459 } else { 1460 mApnContexts.remove(dp.mApnContext); 1461 notifyDisconnectCompleted(dp, false); 1462 } 1463 } else { 1464 log("DcActiveState ERROR no such apnContext=" + dp.mApnContext 1465 + " in this dc=" + DataConnection.this); 1466 notifyDisconnectCompleted(dp, false); 1467 } 1468 retVal = HANDLED; 1469 break; 1470 } 1471 case EVENT_DISCONNECT_ALL: { 1472 if (DBG) { 1473 log("DcActiveState EVENT_DISCONNECT clearing apn contexts," 1474 + " dc=" + DataConnection.this); 1475 } 1476 DisconnectParams dp = (DisconnectParams) msg.obj; 1477 mDisconnectParams = dp; 1478 mConnectionParams = null; 1479 dp.mTag = mTag; 1480 tearDownData(dp); 1481 transitionTo(mDisconnectingState); 1482 retVal = HANDLED; 1483 break; 1484 } 1485 case EVENT_LOST_CONNECTION: { 1486 if (DBG) { 1487 log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this); 1488 } 1489 if (mRetryManager.isRetryNeeded()) { 1490 // We're going to retry 1491 int delayMillis = mRetryManager.getRetryTimer(); 1492 if (DBG) { 1493 log("DcActiveState EVENT_LOST_CONNECTION startRetryAlarm" 1494 + " mTag=" + mTag + " delay=" + delayMillis + "ms"); 1495 } 1496 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag, 1497 delayMillis); 1498 transitionTo(mRetryingState); 1499 } else { 1500 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION); 1501 transitionTo(mInactiveState); 1502 } 1503 retVal = HANDLED; 1504 break; 1505 } 1506 default: 1507 if (VDBG) { 1508 log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); 1509 } 1510 retVal = NOT_HANDLED; 1511 break; 1512 } 1513 return retVal; 1514 } 1515 } 1516 private DcActiveState mActiveState = new DcActiveState(); 1517 1518 /** 1519 * The state machine is disconnecting. 1520 */ 1521 private class DcDisconnectingState extends State { 1522 @Override 1523 public boolean processMessage(Message msg) { 1524 boolean retVal; 1525 1526 switch (msg.what) { 1527 case EVENT_CONNECT: 1528 if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " 1529 + mApnContexts.size()); 1530 deferMessage(msg); 1531 retVal = HANDLED; 1532 break; 1533 1534 case EVENT_DEACTIVATE_DONE: 1535 if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=" 1536 + mApnContexts.size()); 1537 AsyncResult ar = (AsyncResult) msg.obj; 1538 DisconnectParams dp = (DisconnectParams) ar.userObj; 1539 if (dp.mTag == mTag) { 1540 // Transition to inactive but send notifications after 1541 // we've entered the mInactive state. 1542 mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj); 1543 transitionTo(mInactiveState); 1544 } else { 1545 if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE" 1546 + " dp.tag=" + dp.mTag + " mTag=" + mTag); 1547 } 1548 retVal = HANDLED; 1549 break; 1550 1551 default: 1552 if (VDBG) { 1553 log("DcDisconnectingState not handled msg.what=" 1554 + getWhatToString(msg.what)); 1555 } 1556 retVal = NOT_HANDLED; 1557 break; 1558 } 1559 return retVal; 1560 } 1561 } 1562 private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); 1563 1564 /** 1565 * The state machine is disconnecting after an creating a connection. 1566 */ 1567 private class DcDisconnectionErrorCreatingConnection extends State { 1568 @Override 1569 public boolean processMessage(Message msg) { 1570 boolean retVal; 1571 1572 switch (msg.what) { 1573 case EVENT_DEACTIVATE_DONE: 1574 AsyncResult ar = (AsyncResult) msg.obj; 1575 ConnectionParams cp = (ConnectionParams) ar.userObj; 1576 if (cp.mTag == mTag) { 1577 if (DBG) { 1578 log("DcDisconnectionErrorCreatingConnection" + 1579 " msg.what=EVENT_DEACTIVATE_DONE"); 1580 } 1581 1582 // Transition to inactive but send notifications after 1583 // we've entered the mInactive state. 1584 mInactiveState.setEnterNotificationParams(cp, 1585 DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER); 1586 transitionTo(mInactiveState); 1587 } else { 1588 if (DBG) { 1589 log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE" 1590 + " dp.tag=" + cp.mTag + ", mTag=" + mTag); 1591 } 1592 } 1593 retVal = HANDLED; 1594 break; 1595 1596 default: 1597 if (VDBG) { 1598 log("DcDisconnectionErrorCreatingConnection not handled msg.what=" 1599 + getWhatToString(msg.what)); 1600 } 1601 retVal = NOT_HANDLED; 1602 break; 1603 } 1604 return retVal; 1605 } 1606 } 1607 private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = 1608 new DcDisconnectionErrorCreatingConnection(); 1609 1610 // ******* "public" interface 1611 1612 /** 1613 * Used for testing purposes. 1614 */ 1615 /* package */ void tearDownNow() { 1616 if (DBG) log("tearDownNow()"); 1617 sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW)); 1618 } 1619 1620 /** 1621 * @return the string for msg.what as our info. 1622 */ 1623 @Override 1624 protected String getWhatToString(int what) { 1625 return cmdToString(what); 1626 } 1627 1628 private static String msgToString(Message msg) { 1629 String retVal; 1630 if (msg == null) { 1631 retVal = "null"; 1632 } else { 1633 StringBuilder b = new StringBuilder(); 1634 1635 b.append("{what="); 1636 b.append(cmdToString(msg.what)); 1637 1638 b.append(" when="); 1639 TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b); 1640 1641 if (msg.arg1 != 0) { 1642 b.append(" arg1="); 1643 b.append(msg.arg1); 1644 } 1645 1646 if (msg.arg2 != 0) { 1647 b.append(" arg2="); 1648 b.append(msg.arg2); 1649 } 1650 1651 if (msg.obj != null) { 1652 b.append(" obj="); 1653 b.append(msg.obj); 1654 } 1655 1656 b.append(" target="); 1657 b.append(msg.getTarget()); 1658 1659 b.append(" replyTo="); 1660 b.append(msg.replyTo); 1661 1662 b.append("}"); 1663 1664 retVal = b.toString(); 1665 } 1666 return retVal; 1667 } 1668 1669 static void slog(String s) { 1670 Rlog.d("DC", s); 1671 } 1672 1673 /** 1674 * Log with debug 1675 * 1676 * @param s is string log 1677 */ 1678 @Override 1679 protected void log(String s) { 1680 Rlog.d(getName(), s); 1681 } 1682 1683 /** 1684 * Log with debug attribute 1685 * 1686 * @param s is string log 1687 */ 1688 @Override 1689 protected void logd(String s) { 1690 Rlog.d(getName(), s); 1691 } 1692 1693 /** 1694 * Log with verbose attribute 1695 * 1696 * @param s is string log 1697 */ 1698 @Override 1699 protected void logv(String s) { 1700 Rlog.v(getName(), s); 1701 } 1702 1703 /** 1704 * Log with info attribute 1705 * 1706 * @param s is string log 1707 */ 1708 @Override 1709 protected void logi(String s) { 1710 Rlog.i(getName(), s); 1711 } 1712 1713 /** 1714 * Log with warning attribute 1715 * 1716 * @param s is string log 1717 */ 1718 @Override 1719 protected void logw(String s) { 1720 Rlog.w(getName(), s); 1721 } 1722 1723 /** 1724 * Log with error attribute 1725 * 1726 * @param s is string log 1727 */ 1728 @Override 1729 protected void loge(String s) { 1730 Rlog.e(getName(), s); 1731 } 1732 1733 /** 1734 * Log with error attribute 1735 * 1736 * @param s is string log 1737 * @param e is a Throwable which logs additional information. 1738 */ 1739 @Override 1740 protected void loge(String s, Throwable e) { 1741 Rlog.e(getName(), s, e); 1742 } 1743 1744 /** Doesn't print mApnList of ApnContext's which would be recursive */ 1745 public String toStringSimple() { 1746 return getName() + ": State=" + getCurrentState().getName() 1747 + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size() 1748 + " mCid=" + mCid + " mCreateTime=" + mCreateTime 1749 + " mLastastFailTime=" + mLastFailTime 1750 + " mLastFailCause=" + mLastFailCause 1751 + " mTag=" + mTag 1752 + " mRetryManager=" + mRetryManager 1753 + " mLinkProperties=" + mLinkProperties 1754 + " mLinkCapabilities=" + mLinkCapabilities; 1755 } 1756 1757 @Override 1758 public String toString() { 1759 return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}"; 1760 } 1761 1762 /** 1763 * Dump the current state. 1764 * 1765 * @param fd 1766 * @param pw 1767 * @param args 1768 */ 1769 @Override 1770 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1771 pw.print("DataConnection "); 1772 super.dump(fd, pw, args); 1773 pw.println(" mApnContexts.size=" + mApnContexts.size()); 1774 pw.println(" mApnContexts=" + mApnContexts); 1775 pw.flush(); 1776 pw.println(" mDataConnectionTracker=" + mDct); 1777 pw.println(" mApnSetting=" + mApnSetting); 1778 pw.println(" mTag=" + mTag); 1779 pw.println(" mCid=" + mCid); 1780 pw.println(" mRetryManager=" + mRetryManager); 1781 pw.println(" mConnectionParams=" + mConnectionParams); 1782 pw.println(" mDisconnectParams=" + mDisconnectParams); 1783 pw.println(" mDcFailCause=" + mDcFailCause); 1784 pw.flush(); 1785 pw.println(" mPhone=" + mPhone); 1786 pw.flush(); 1787 pw.println(" mLinkProperties=" + mLinkProperties); 1788 pw.flush(); 1789 pw.println(" mDataRegState=" + mDataRegState); 1790 pw.println(" mRilRat=" + mRilRat); 1791 pw.println(" mLinkCapabilities=" + mLinkCapabilities); 1792 pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime)); 1793 pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); 1794 pw.println(" mLastFailCause=" + mLastFailCause); 1795 pw.flush(); 1796 pw.println(" mUserData=" + mUserData); 1797 pw.println(" mInstanceNumber=" + mInstanceNumber); 1798 pw.println(" mAc=" + mAc); 1799 pw.println(" mDcRetryAlarmController=" + mDcRetryAlarmController); 1800 pw.flush(); 1801 } 1802 } 1803