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 deferMessage(msg); 1201 transitionTo(mInactiveState); 1202 retVal = HANDLED; 1203 break; 1204 } 1205 default: { 1206 if (VDBG) { 1207 log("DcRetryingState nothandled msg.what=" + getWhatToString(msg.what)); 1208 } 1209 retVal = NOT_HANDLED; 1210 break; 1211 } 1212 } 1213 return retVal; 1214 } 1215 } 1216 private DcRetryingState mRetryingState = new DcRetryingState(); 1217 1218 /** 1219 * The state machine is activating a connection. 1220 */ 1221 private class DcActivatingState extends State { 1222 @Override 1223 public boolean processMessage(Message msg) { 1224 boolean retVal; 1225 AsyncResult ar; 1226 ConnectionParams cp; 1227 1228 if (DBG) log("DcActivatingState: msg=" + msgToString(msg)); 1229 switch (msg.what) { 1230 case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: 1231 case EVENT_CONNECT: 1232 // Activating can't process until we're done. 1233 deferMessage(msg); 1234 retVal = HANDLED; 1235 break; 1236 1237 case EVENT_SETUP_DATA_CONNECTION_DONE: 1238 ar = (AsyncResult) msg.obj; 1239 cp = (ConnectionParams) ar.userObj; 1240 1241 DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar); 1242 if (result != DataCallResponse.SetupResult.ERR_Stale) { 1243 if (mConnectionParams != cp) { 1244 loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams 1245 + " != cp:" + cp); 1246 } 1247 } 1248 if (DBG) { 1249 log("DcActivatingState onSetupConnectionCompleted result=" + result 1250 + " dc=" + DataConnection.this); 1251 } 1252 switch (result) { 1253 case SUCCESS: 1254 // All is well 1255 mDcFailCause = DcFailCause.NONE; 1256 transitionTo(mActiveState); 1257 break; 1258 case ERR_BadCommand: 1259 // Vendor ril rejected the command and didn't connect. 1260 // Transition to inactive but send notifications after 1261 // we've entered the mInactive state. 1262 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1263 transitionTo(mInactiveState); 1264 break; 1265 case ERR_UnacceptableParameter: 1266 // The addresses given from the RIL are bad 1267 tearDownData(cp); 1268 transitionTo(mDisconnectingErrorCreatingConnection); 1269 break; 1270 case ERR_GetLastErrorFromRil: 1271 // Request failed and this is an old RIL 1272 mPhone.mCi.getLastDataCallFailCause( 1273 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp)); 1274 break; 1275 case ERR_RilError: 1276 int delay = mDcRetryAlarmController.getSuggestedRetryTime( 1277 DataConnection.this, ar); 1278 if (DBG) { 1279 log("DcActivatingState: ERR_RilError " 1280 + " delay=" + delay 1281 + " isRetryNeeded=" + mRetryManager.isRetryNeeded() 1282 + " result=" + result 1283 + " result.isRestartRadioFail=" + 1284 result.mFailCause.isRestartRadioFail() 1285 + " result.isPermanentFail=" + 1286 result.mFailCause.isPermanentFail()); 1287 } 1288 if (result.mFailCause.isRestartRadioFail()) { 1289 if (DBG) log("DcActivatingState: ERR_RilError restart radio"); 1290 mDct.sendRestartRadio(); 1291 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1292 transitionTo(mInactiveState); 1293 } else if (result.mFailCause.isPermanentFail()) { 1294 if (DBG) log("DcActivatingState: ERR_RilError perm error"); 1295 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1296 transitionTo(mInactiveState); 1297 } else if (delay >= 0) { 1298 if (DBG) log("DcActivatingState: ERR_RilError retry"); 1299 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, 1300 mTag, delay); 1301 transitionTo(mRetryingState); 1302 } else { 1303 if (DBG) log("DcActivatingState: ERR_RilError no retry"); 1304 mInactiveState.setEnterNotificationParams(cp, result.mFailCause); 1305 transitionTo(mInactiveState); 1306 } 1307 break; 1308 case ERR_Stale: 1309 loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE" 1310 + " tag:" + cp.mTag + " != mTag:" + mTag); 1311 break; 1312 default: 1313 throw new RuntimeException("Unknown SetupResult, should not happen"); 1314 } 1315 retVal = HANDLED; 1316 break; 1317 1318 case EVENT_GET_LAST_FAIL_DONE: 1319 ar = (AsyncResult) msg.obj; 1320 cp = (ConnectionParams) ar.userObj; 1321 if (cp.mTag == mTag) { 1322 if (mConnectionParams != cp) { 1323 loge("DcActivatingState: WEIRD mConnectionsParams:" + mConnectionParams 1324 + " != cp:" + cp); 1325 } 1326 1327 DcFailCause cause = DcFailCause.UNKNOWN; 1328 1329 if (ar.exception == null) { 1330 int rilFailCause = ((int[]) (ar.result))[0]; 1331 cause = DcFailCause.fromInt(rilFailCause); 1332 if (cause == DcFailCause.NONE) { 1333 if (DBG) { 1334 log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE" 1335 + " BAD: error was NONE, change to UNKNOWN"); 1336 } 1337 cause = DcFailCause.UNKNOWN; 1338 } 1339 } 1340 mDcFailCause = cause; 1341 1342 int retryDelay = mRetryManager.getRetryTimer(); 1343 if (DBG) { 1344 log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE" 1345 + " cause=" + cause 1346 + " retryDelay=" + retryDelay 1347 + " isRetryNeeded=" + mRetryManager.isRetryNeeded() 1348 + " dc=" + DataConnection.this); 1349 } 1350 if (cause.isRestartRadioFail()) { 1351 if (DBG) { 1352 log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE" 1353 + " restart radio"); 1354 } 1355 mDct.sendRestartRadio(); 1356 mInactiveState.setEnterNotificationParams(cp, cause); 1357 transitionTo(mInactiveState); 1358 } else if (cause.isPermanentFail()) { 1359 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE perm er"); 1360 mInactiveState.setEnterNotificationParams(cp, cause); 1361 transitionTo(mInactiveState); 1362 } else if ((retryDelay >= 0) && (mRetryManager.isRetryNeeded())) { 1363 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE retry"); 1364 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag, 1365 retryDelay); 1366 transitionTo(mRetryingState); 1367 } else { 1368 if (DBG) log("DcActivatingState: EVENT_GET_LAST_FAIL_DONE no retry"); 1369 mInactiveState.setEnterNotificationParams(cp, cause); 1370 transitionTo(mInactiveState); 1371 } 1372 } else { 1373 loge("DcActivatingState: stale EVENT_GET_LAST_FAIL_DONE" 1374 + " tag:" + cp.mTag + " != mTag:" + mTag); 1375 } 1376 1377 retVal = HANDLED; 1378 break; 1379 1380 default: 1381 if (VDBG) { 1382 log("DcActivatingState not handled msg.what=" + 1383 getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); 1384 } 1385 retVal = NOT_HANDLED; 1386 break; 1387 } 1388 return retVal; 1389 } 1390 } 1391 private DcActivatingState mActivatingState = new DcActivatingState(); 1392 1393 /** 1394 * The state machine is connected, expecting an EVENT_DISCONNECT. 1395 */ 1396 private class DcActiveState extends State { 1397 @Override public void enter() { 1398 if (DBG) log("DcActiveState: enter dc=" + DataConnection.this); 1399 1400 if (mRetryManager.getRetryCount() != 0) { 1401 log("DcActiveState: connected after retrying call notifyAllOfConnected"); 1402 mRetryManager.setRetryCount(0); 1403 } 1404 // If we were retrying there maybe more than one, otherwise they'll only be one. 1405 notifyAllOfConnected(Phone.REASON_CONNECTED); 1406 1407 // If the EVENT_CONNECT set the current max retry restore it here 1408 // if it didn't then this is effectively a NOP. 1409 mRetryManager.restoreCurMaxRetryCount(); 1410 mDcController.addActiveDcByCid(DataConnection.this); 1411 } 1412 1413 @Override 1414 public void exit() { 1415 if (DBG) log("DcActiveState: exit dc=" + this); 1416 } 1417 1418 @Override 1419 public boolean processMessage(Message msg) { 1420 boolean retVal; 1421 1422 switch (msg.what) { 1423 case EVENT_CONNECT: { 1424 ConnectionParams cp = (ConnectionParams) msg.obj; 1425 if (DBG) { 1426 log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this); 1427 } 1428 if (mApnContexts.contains(cp.mApnContext)) { 1429 log("DcActiveState ERROR already added apnContext=" + cp.mApnContext); 1430 } else { 1431 mApnContexts.add(cp.mApnContext); 1432 if (DBG) { 1433 log("DcActiveState msg.what=EVENT_CONNECT RefCount=" 1434 + mApnContexts.size()); 1435 } 1436 } 1437 notifyConnectCompleted(cp, DcFailCause.NONE, false); 1438 retVal = HANDLED; 1439 break; 1440 } 1441 case EVENT_DISCONNECT: { 1442 DisconnectParams dp = (DisconnectParams) msg.obj; 1443 if (DBG) { 1444 log("DcActiveState: EVENT_DISCONNECT dp=" + dp 1445 + " dc=" + DataConnection.this); 1446 } 1447 if (mApnContexts.contains(dp.mApnContext)) { 1448 if (DBG) { 1449 log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" 1450 + mApnContexts.size()); 1451 } 1452 1453 if (mApnContexts.size() == 1) { 1454 mApnContexts.clear(); 1455 mDisconnectParams = dp; 1456 mConnectionParams = null; 1457 dp.mTag = mTag; 1458 tearDownData(dp); 1459 transitionTo(mDisconnectingState); 1460 } else { 1461 mApnContexts.remove(dp.mApnContext); 1462 notifyDisconnectCompleted(dp, false); 1463 } 1464 } else { 1465 log("DcActiveState ERROR no such apnContext=" + dp.mApnContext 1466 + " in this dc=" + DataConnection.this); 1467 notifyDisconnectCompleted(dp, false); 1468 } 1469 retVal = HANDLED; 1470 break; 1471 } 1472 case EVENT_DISCONNECT_ALL: { 1473 if (DBG) { 1474 log("DcActiveState EVENT_DISCONNECT clearing apn contexts," 1475 + " dc=" + DataConnection.this); 1476 } 1477 mApnContexts.clear(); 1478 DisconnectParams dp = (DisconnectParams) msg.obj; 1479 mDisconnectParams = dp; 1480 mConnectionParams = null; 1481 dp.mTag = mTag; 1482 tearDownData(dp); 1483 transitionTo(mDisconnectingState); 1484 retVal = HANDLED; 1485 break; 1486 } 1487 case EVENT_LOST_CONNECTION: { 1488 if (DBG) { 1489 log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this); 1490 } 1491 if (mRetryManager.isRetryNeeded()) { 1492 // We're going to retry 1493 int delayMillis = mRetryManager.getRetryTimer(); 1494 if (DBG) { 1495 log("DcActiveState EVENT_LOST_CONNECTION startRetryAlarm" 1496 + " mTag=" + mTag + " delay=" + delayMillis + "ms"); 1497 } 1498 mDcRetryAlarmController.startRetryAlarm(EVENT_RETRY_CONNECTION, mTag, 1499 delayMillis); 1500 transitionTo(mRetryingState); 1501 } else { 1502 mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION); 1503 transitionTo(mInactiveState); 1504 } 1505 retVal = HANDLED; 1506 break; 1507 } 1508 default: 1509 if (VDBG) { 1510 log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); 1511 } 1512 retVal = NOT_HANDLED; 1513 break; 1514 } 1515 return retVal; 1516 } 1517 } 1518 private DcActiveState mActiveState = new DcActiveState(); 1519 1520 /** 1521 * The state machine is disconnecting. 1522 */ 1523 private class DcDisconnectingState extends State { 1524 @Override 1525 public boolean processMessage(Message msg) { 1526 boolean retVal; 1527 1528 switch (msg.what) { 1529 case EVENT_CONNECT: 1530 if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " 1531 + mApnContexts.size()); 1532 deferMessage(msg); 1533 retVal = HANDLED; 1534 break; 1535 1536 case EVENT_DEACTIVATE_DONE: 1537 if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=" 1538 + mApnContexts.size()); 1539 AsyncResult ar = (AsyncResult) msg.obj; 1540 DisconnectParams dp = (DisconnectParams) ar.userObj; 1541 if (dp.mTag == mTag) { 1542 // Transition to inactive but send notifications after 1543 // we've entered the mInactive state. 1544 mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj); 1545 transitionTo(mInactiveState); 1546 } else { 1547 if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE" 1548 + " dp.tag=" + dp.mTag + " mTag=" + mTag); 1549 } 1550 retVal = HANDLED; 1551 break; 1552 1553 default: 1554 if (VDBG) { 1555 log("DcDisconnectingState not handled msg.what=" 1556 + getWhatToString(msg.what)); 1557 } 1558 retVal = NOT_HANDLED; 1559 break; 1560 } 1561 return retVal; 1562 } 1563 } 1564 private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); 1565 1566 /** 1567 * The state machine is disconnecting after an creating a connection. 1568 */ 1569 private class DcDisconnectionErrorCreatingConnection extends State { 1570 @Override 1571 public boolean processMessage(Message msg) { 1572 boolean retVal; 1573 1574 switch (msg.what) { 1575 case EVENT_DEACTIVATE_DONE: 1576 AsyncResult ar = (AsyncResult) msg.obj; 1577 ConnectionParams cp = (ConnectionParams) ar.userObj; 1578 if (cp.mTag == mTag) { 1579 if (DBG) { 1580 log("DcDisconnectionErrorCreatingConnection" + 1581 " msg.what=EVENT_DEACTIVATE_DONE"); 1582 } 1583 1584 // Transition to inactive but send notifications after 1585 // we've entered the mInactive state. 1586 mInactiveState.setEnterNotificationParams(cp, 1587 DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER); 1588 transitionTo(mInactiveState); 1589 } else { 1590 if (DBG) { 1591 log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE" 1592 + " dp.tag=" + cp.mTag + ", mTag=" + mTag); 1593 } 1594 } 1595 retVal = HANDLED; 1596 break; 1597 1598 default: 1599 if (VDBG) { 1600 log("DcDisconnectionErrorCreatingConnection not handled msg.what=" 1601 + getWhatToString(msg.what)); 1602 } 1603 retVal = NOT_HANDLED; 1604 break; 1605 } 1606 return retVal; 1607 } 1608 } 1609 private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = 1610 new DcDisconnectionErrorCreatingConnection(); 1611 1612 // ******* "public" interface 1613 1614 /** 1615 * Used for testing purposes. 1616 */ 1617 /* package */ void tearDownNow() { 1618 if (DBG) log("tearDownNow()"); 1619 sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW)); 1620 } 1621 1622 /** 1623 * @return the string for msg.what as our info. 1624 */ 1625 @Override 1626 protected String getWhatToString(int what) { 1627 return cmdToString(what); 1628 } 1629 1630 private static String msgToString(Message msg) { 1631 String retVal; 1632 if (msg == null) { 1633 retVal = "null"; 1634 } else { 1635 StringBuilder b = new StringBuilder(); 1636 1637 b.append("{what="); 1638 b.append(cmdToString(msg.what)); 1639 1640 b.append(" when="); 1641 TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b); 1642 1643 if (msg.arg1 != 0) { 1644 b.append(" arg1="); 1645 b.append(msg.arg1); 1646 } 1647 1648 if (msg.arg2 != 0) { 1649 b.append(" arg2="); 1650 b.append(msg.arg2); 1651 } 1652 1653 if (msg.obj != null) { 1654 b.append(" obj="); 1655 b.append(msg.obj); 1656 } 1657 1658 b.append(" target="); 1659 b.append(msg.getTarget()); 1660 1661 b.append(" replyTo="); 1662 b.append(msg.replyTo); 1663 1664 b.append("}"); 1665 1666 retVal = b.toString(); 1667 } 1668 return retVal; 1669 } 1670 1671 static void slog(String s) { 1672 Rlog.d("DC", s); 1673 } 1674 1675 /** 1676 * Log with debug 1677 * 1678 * @param s is string log 1679 */ 1680 @Override 1681 protected void log(String s) { 1682 Rlog.d(getName(), s); 1683 } 1684 1685 /** 1686 * Log with debug attribute 1687 * 1688 * @param s is string log 1689 */ 1690 @Override 1691 protected void logd(String s) { 1692 Rlog.d(getName(), s); 1693 } 1694 1695 /** 1696 * Log with verbose attribute 1697 * 1698 * @param s is string log 1699 */ 1700 @Override 1701 protected void logv(String s) { 1702 Rlog.v(getName(), s); 1703 } 1704 1705 /** 1706 * Log with info attribute 1707 * 1708 * @param s is string log 1709 */ 1710 @Override 1711 protected void logi(String s) { 1712 Rlog.i(getName(), s); 1713 } 1714 1715 /** 1716 * Log with warning attribute 1717 * 1718 * @param s is string log 1719 */ 1720 @Override 1721 protected void logw(String s) { 1722 Rlog.w(getName(), s); 1723 } 1724 1725 /** 1726 * Log with error attribute 1727 * 1728 * @param s is string log 1729 */ 1730 @Override 1731 protected void loge(String s) { 1732 Rlog.e(getName(), s); 1733 } 1734 1735 /** 1736 * Log with error attribute 1737 * 1738 * @param s is string log 1739 * @param e is a Throwable which logs additional information. 1740 */ 1741 @Override 1742 protected void loge(String s, Throwable e) { 1743 Rlog.e(getName(), s, e); 1744 } 1745 1746 /** Doesn't print mApnList of ApnContext's which would be recursive */ 1747 public String toStringSimple() { 1748 return getName() + ": State=" + getCurrentState().getName() 1749 + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size() 1750 + " mCid=" + mCid + " mCreateTime=" + mCreateTime 1751 + " mLastastFailTime=" + mLastFailTime 1752 + " mLastFailCause=" + mLastFailCause 1753 + " mTag=" + mTag 1754 + " mRetryManager=" + mRetryManager 1755 + " mLinkProperties=" + mLinkProperties 1756 + " mLinkCapabilities=" + mLinkCapabilities; 1757 } 1758 1759 @Override 1760 public String toString() { 1761 return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}"; 1762 } 1763 1764 /** 1765 * Dump the current state. 1766 * 1767 * @param fd 1768 * @param pw 1769 * @param args 1770 */ 1771 @Override 1772 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1773 pw.print("DataConnection "); 1774 super.dump(fd, pw, args); 1775 pw.println(" mApnContexts.size=" + mApnContexts.size()); 1776 pw.println(" mApnContexts=" + mApnContexts); 1777 pw.flush(); 1778 pw.println(" mDataConnectionTracker=" + mDct); 1779 pw.println(" mApnSetting=" + mApnSetting); 1780 pw.println(" mTag=" + mTag); 1781 pw.println(" mCid=" + mCid); 1782 pw.println(" mRetryManager=" + mRetryManager); 1783 pw.println(" mConnectionParams=" + mConnectionParams); 1784 pw.println(" mDisconnectParams=" + mDisconnectParams); 1785 pw.println(" mDcFailCause=" + mDcFailCause); 1786 pw.flush(); 1787 pw.println(" mPhone=" + mPhone); 1788 pw.flush(); 1789 pw.println(" mLinkProperties=" + mLinkProperties); 1790 pw.flush(); 1791 pw.println(" mDataRegState=" + mDataRegState); 1792 pw.println(" mRilRat=" + mRilRat); 1793 pw.println(" mLinkCapabilities=" + mLinkCapabilities); 1794 pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime)); 1795 pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); 1796 pw.println(" mLastFailCause=" + mLastFailCause); 1797 pw.flush(); 1798 pw.println(" mUserData=" + mUserData); 1799 pw.println(" mInstanceNumber=" + mInstanceNumber); 1800 pw.println(" mAc=" + mAc); 1801 pw.println(" mDcRetryAlarmController=" + mDcRetryAlarmController); 1802 pw.flush(); 1803 } 1804 } 1805