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