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