GsmDataConnectionTracker.java revision 37b80ee451a7404c288738255725f78a5af02130
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.gsm; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.content.BroadcastReceiver; 22import android.content.ContentResolver; 23import android.content.ContentValues; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.SharedPreferences; 28import android.database.ContentObserver; 29import android.database.Cursor; 30import android.net.NetworkInfo; 31import android.net.Uri; 32import android.net.wifi.WifiManager; 33import android.os.AsyncResult; 34import android.os.INetStatService; 35import android.os.Message; 36import android.os.RemoteException; 37import android.os.ServiceManager; 38import android.os.SystemClock; 39import android.os.SystemProperties; 40import android.preference.PreferenceManager; 41import android.provider.Checkin; 42import android.provider.Settings; 43import android.provider.Telephony; 44import android.telephony.ServiceState; 45import android.telephony.TelephonyManager; 46import android.telephony.gsm.GsmCellLocation; 47import android.text.TextUtils; 48import android.util.EventLog; 49import android.util.Log; 50 51import com.android.internal.telephony.DataCallState; 52import com.android.internal.telephony.DataConnection; 53import com.android.internal.telephony.DataConnectionTracker; 54import com.android.internal.telephony.Phone; 55import com.android.internal.telephony.RetryManager; 56import com.android.internal.telephony.TelephonyEventLog; 57import com.android.internal.telephony.DataConnection.FailCause; 58 59import java.io.IOException; 60import java.util.ArrayList; 61 62/** 63 * {@hide} 64 */ 65public final class GsmDataConnectionTracker extends DataConnectionTracker { 66 protected final String LOG_TAG = "GSM"; 67 68 private GSMPhone mGsmPhone; 69 /** 70 * Handles changes to the APN db. 71 */ 72 private class ApnChangeObserver extends ContentObserver { 73 public ApnChangeObserver () { 74 super(mDataConnectionTracker); 75 } 76 77 @Override 78 public void onChange(boolean selfChange) { 79 sendMessage(obtainMessage(EVENT_APN_CHANGED)); 80 } 81 } 82 83 //***** Instance Variables 84 85 INetStatService netstat; 86 // Indicates baseband will not auto-attach 87 private boolean noAutoAttach = false; 88 89 private boolean mReregisterOnReconnectFailure = false; 90 private ContentResolver mResolver; 91 92 private boolean mPingTestActive = false; 93 // Count of PDP reset attempts; reset when we see incoming, 94 // call reRegisterNetwork, or pingTest succeeds. 95 private int mPdpResetCount = 0; 96 private boolean mIsScreenOn = true; 97 98 /** Delay between APN attempts */ 99 protected static final int APN_DELAY_MILLIS = 5000; 100 101 //useful for debugging 102 boolean failNextConnect = false; 103 104 /** 105 * allApns holds all apns for this sim spn, retrieved from 106 * the Carrier DB. 107 * 108 * Create once after simcard info is loaded 109 */ 110 private ArrayList<ApnSetting> allApns = null; 111 112 /** 113 * waitingApns holds all apns that are waiting to be connected 114 * 115 * It is a subset of allApns and has the same format 116 */ 117 private ArrayList<ApnSetting> waitingApns = null; 118 119 private ApnSetting preferredApn = null; 120 121 /* Currently active APN */ 122 protected ApnSetting mActiveApn; 123 124 /** 125 * pdpList holds all the PDP connection, i.e. IP Link in GPRS 126 */ 127 private ArrayList<DataConnection> pdpList; 128 129 /** Currently active PdpConnection */ 130 private PdpConnection mActivePdp; 131 132 /** Is packet service restricted by network */ 133 private boolean mIsPsRestricted = false; 134 135 //***** Constants 136 137 // TODO: Increase this to match the max number of simultaneous 138 // PDP contexts we plan to support. 139 /** 140 * Pool size of PdpConnection objects. 141 */ 142 private static final int PDP_CONNECTION_POOL_SIZE = 1; 143 144 private static final int POLL_PDP_MILLIS = 5 * 1000; 145 146 private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; 147 private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; 148 149 static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); 150 static final String APN_ID = "apn_id"; 151 private boolean canSetPreferApn = false; 152 153 // for tracking retrys on the default APN 154 private RetryManager mDefaultRetryManager; 155 // for tracking retrys on a secondary APN 156 private RetryManager mSecondaryRetryManager; 157 158 BroadcastReceiver mIntentReceiver = new BroadcastReceiver () 159 { 160 @Override 161 public void onReceive(Context context, Intent intent) 162 { 163 String action = intent.getAction(); 164 if (action.equals(Intent.ACTION_SCREEN_ON)) { 165 mIsScreenOn = true; 166 stopNetStatPoll(); 167 startNetStatPoll(); 168 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 169 mIsScreenOn = false; 170 stopNetStatPoll(); 171 startNetStatPoll(); 172 } else if (action.equals((INTENT_RECONNECT_ALARM))) { 173 Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); 174 175 String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); 176 if (state == State.FAILED) { 177 Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); 178 msg.arg1 = 0; // tearDown is false 179 msg.obj = (String) reason; 180 sendMessage(msg); 181 } 182 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); 183 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 184 final android.net.NetworkInfo networkInfo = (NetworkInfo) 185 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 186 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); 187 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 188 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 189 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 190 191 if (!enabled) { 192 // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION 193 // quit and wont report disconnected til next enalbing. 194 mIsWifiConnected = false; 195 } 196 } 197 } 198 }; 199 200 /** Watches for changes to the APN db. */ 201 private ApnChangeObserver apnObserver; 202 203 //***** Constructor 204 205 GsmDataConnectionTracker(GSMPhone p) { 206 super(p); 207 mGsmPhone = p; 208 p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); 209 p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 210 p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); 211 p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); 212 p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); 213 p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); 214 p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); 215 p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); 216 p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); 217 p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); 218 p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); 219 p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); 220 221 this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); 222 223 IntentFilter filter = new IntentFilter(); 224 filter.addAction(INTENT_RECONNECT_ALARM); 225 filter.addAction(Intent.ACTION_SCREEN_ON); 226 filter.addAction(Intent.ACTION_SCREEN_OFF); 227 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 228 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 229 230 // TODO: Why is this registering the phone as the receiver of the intent 231 // and not its own handler? 232 p.getContext().registerReceiver(mIntentReceiver, filter, null, p); 233 234 235 mDataConnectionTracker = this; 236 mResolver = phone.getContext().getContentResolver(); 237 238 apnObserver = new ApnChangeObserver(); 239 p.getContext().getContentResolver().registerContentObserver( 240 Telephony.Carriers.CONTENT_URI, true, apnObserver); 241 242 createAllPdpList(); 243 244 // This preference tells us 1) initial condition for "dataEnabled", 245 // and 2) whether the RIL will setup the baseband to auto-PS attach. 246 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); 247 dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false); 248 if (dataEnabled[APN_DEFAULT_ID]) { 249 enabledCount++; 250 } 251 noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; 252 253 if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { 254 if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { 255 // Should never happen, log an error and default to a simple linear sequence. 256 Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" 257 + DEFAULT_DATA_RETRY_CONFIG); 258 mRetryMgr.configure(20, 2000, 1000); 259 } 260 } 261 262 mDefaultRetryManager = mRetryMgr; 263 mSecondaryRetryManager = new RetryManager(); 264 265 if (!mSecondaryRetryManager.configure(SystemProperties.get( 266 "ro.gsm.2nd_data_retry_config"))) { 267 if (!mSecondaryRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) { 268 // Should never happen, log an error and default to a simple sequence. 269 Log.e(LOG_TAG, "Could note configure using SECONDARY_DATA_RETRY_CONFIG=" 270 + SECONDARY_DATA_RETRY_CONFIG); 271 mSecondaryRetryManager.configure("max_retries=3, 333, 333, 333"); 272 } 273 } 274 } 275 276 public void dispose() { 277 //Unregister for all events 278 phone.mCM.unregisterForAvailable(this); 279 phone.mCM.unregisterForOffOrNotAvailable(this); 280 mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this); 281 phone.mCM.unregisterForDataStateChanged(this); 282 mGsmPhone.mCT.unregisterForVoiceCallEnded(this); 283 mGsmPhone.mCT.unregisterForVoiceCallStarted(this); 284 mGsmPhone.mSST.unregisterForGprsAttached(this); 285 mGsmPhone.mSST.unregisterForGprsDetached(this); 286 mGsmPhone.mSST.unregisterForRoamingOn(this); 287 mGsmPhone.mSST.unregisterForRoamingOff(this); 288 mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this); 289 mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this); 290 291 phone.getContext().unregisterReceiver(this.mIntentReceiver); 292 phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); 293 294 destroyAllPdpList(); 295 } 296 297 protected void finalize() { 298 if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); 299 } 300 301 protected void setState(State s) { 302 if (DBG) log ("setState: " + s); 303 if (state != s) { 304 if (s == State.INITING) { // request PDP context 305 Checkin.updateStats( 306 phone.getContext().getContentResolver(), 307 Checkin.Stats.Tag.PHONE_GPRS_ATTEMPTED, 1, 0.0); 308 } 309 310 if (s == State.CONNECTED) { // pppd is up 311 Checkin.updateStats( 312 phone.getContext().getContentResolver(), 313 Checkin.Stats.Tag.PHONE_GPRS_CONNECTED, 1, 0.0); 314 } 315 } 316 317 state = s; 318 319 if (state == State.FAILED) { 320 if (waitingApns != null) 321 waitingApns.clear(); // when teardown the connection and set to IDLE 322 } 323 } 324 325 public String[] getActiveApnTypes() { 326 String[] result; 327 if (mActiveApn != null) { 328 result = mActiveApn.types; 329 } else { 330 result = new String[1]; 331 result[0] = Phone.APN_TYPE_DEFAULT; 332 } 333 return result; 334 } 335 336 protected String getActiveApnString() { 337 String result = null; 338 if (mActiveApn != null) { 339 result = mActiveApn.apn; 340 } 341 return result; 342 } 343 344 /** 345 * The data connection is expected to be setup while device 346 * 1. has sim card 347 * 2. registered to gprs service 348 * 3. user doesn't explicitly disable data service 349 * 4. wifi is not on 350 * 351 * @return false while no data connection if all above requirements are met. 352 */ 353 public boolean isDataConnectionAsDesired() { 354 boolean roaming = phone.getServiceState().getRoaming(); 355 356 if (mGsmPhone.mSIMRecords.getRecordsLoaded() && 357 mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && 358 (!roaming || getDataOnRoamingEnabled()) && 359 !mIsWifiConnected && 360 !mIsPsRestricted ) { 361 return (state == State.CONNECTED); 362 } 363 return true; 364 } 365 366 @Override 367 protected boolean isApnTypeActive(String type) { 368 // TODO: support simultaneous with List instead 369 return mActiveApn != null && mActiveApn.canHandleType(type); 370 } 371 372 @Override 373 protected boolean isApnTypeAvailable(String type) { 374 if (allApns != null) { 375 for (ApnSetting apn : allApns) { 376 if (apn.canHandleType(type)) { 377 return true; 378 } 379 } 380 } 381 return false; 382 } 383 384 /** 385 * Formerly this method was ArrayList<PdpConnection> getAllPdps() 386 */ 387 public ArrayList<DataConnection> getAllDataConnections() { 388 ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); 389 return pdps; 390 } 391 392 private boolean isDataAllowed() { 393 boolean roaming = phone.getServiceState().getRoaming(); 394 return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()); 395 } 396 397 //****** Called from ServiceStateTracker 398 /** 399 * Invoked when ServiceStateTracker observes a transition from GPRS 400 * attach to detach. 401 */ 402 protected void onGprsDetached() { 403 /* 404 * We presently believe it is unnecessary to tear down the PDP context 405 * when GPRS detaches, but we should stop the network polling. 406 */ 407 stopNetStatPoll(); 408 phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED); 409 } 410 411 private void onGprsAttached() { 412 if (state == State.CONNECTED) { 413 startNetStatPoll(); 414 phone.notifyDataConnection(Phone.REASON_GPRS_ATTACHED); 415 } else { 416 if (state == State.FAILED) { 417 cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); 418 mRetryMgr.resetRetryCount(); 419 } 420 trySetupData(Phone.REASON_GPRS_ATTACHED); 421 } 422 } 423 424 private boolean trySetupData(String reason) { 425 if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); 426 427 Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); 428 429 if (phone.getSimulatedRadioControl() != null) { 430 // Assume data is connected on the simulator 431 // FIXME this can be improved 432 setState(State.CONNECTED); 433 phone.notifyDataConnection(reason); 434 435 Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); 436 return true; 437 } 438 439 int gprsState = mGsmPhone.mSST.getCurrentGprsState(); 440 boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); 441 442 if ((state == State.IDLE || state == State.SCANNING) 443 && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) 444 && mGsmPhone.mSIMRecords.getRecordsLoaded() 445 && phone.getState() == Phone.State.IDLE 446 && isDataAllowed() 447 && !mIsPsRestricted 448 && desiredPowerState ) { 449 450 if (state == State.IDLE) { 451 waitingApns = buildWaitingApns(); 452 if (waitingApns.isEmpty()) { 453 if (DBG) log("No APN found"); 454 notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); 455 return false; 456 } else { 457 log ("Create from allApns : " + apnListToString(allApns)); 458 } 459 } 460 461 if (DBG) { 462 log ("Setup waitngApns : " + apnListToString(waitingApns)); 463 } 464 return setupData(reason); 465 } else { 466 if (DBG) 467 log("trySetupData: Not ready for data: " + 468 " dataState=" + state + 469 " gprsState=" + gprsState + 470 " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() + 471 " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() + 472 " phoneState=" + phone.getState() + 473 " isDataAllowed=" + isDataAllowed() + 474 " dataEnabled=" + getAnyDataEnabled() + 475 " roaming=" + phone.getServiceState().getRoaming() + 476 " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + 477 " ps restricted=" + mIsPsRestricted + 478 " desiredPowerState=" + desiredPowerState); 479 return false; 480 } 481 } 482 483 /** 484 * If tearDown is true, this only tears down a CONNECTED session. Presently, 485 * there is no mechanism for abandoning an INITING/CONNECTING session, 486 * but would likely involve cancelling pending async requests or 487 * setting a flag or new state to ignore them when they came in 488 * @param tearDown true if the underlying PdpConnection should be 489 * disconnected. 490 * @param reason reason for the clean up. 491 */ 492 private void cleanUpConnection(boolean tearDown, String reason) { 493 if (DBG) log("Clean up connection due to " + reason); 494 495 // Clear the reconnect alarm, if set. 496 if (mReconnectIntent != null) { 497 AlarmManager am = 498 (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); 499 am.cancel(mReconnectIntent); 500 mReconnectIntent = null; 501 } 502 503 setState(State.DISCONNECTING); 504 505 for (DataConnection conn : pdpList) { 506 PdpConnection pdp = (PdpConnection) conn; 507 if (tearDown) { 508 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); 509 pdp.disconnect(msg); 510 } else { 511 pdp.clearSettings(); 512 } 513 } 514 stopNetStatPoll(); 515 516 if (!tearDown) { 517 setState(State.IDLE); 518 phone.notifyDataConnection(reason); 519 mActiveApn = null; 520 } 521 } 522 523 /** 524 * @param types comma delimited list of APN types 525 * @return array of APN types 526 */ 527 private String[] parseTypes(String types) { 528 String[] result; 529 // If unset, set to DEFAULT. 530 if (types == null || types.equals("")) { 531 result = new String[1]; 532 result[0] = Phone.APN_TYPE_ALL; 533 } else { 534 result = types.split(","); 535 } 536 return result; 537 } 538 539 private ArrayList<ApnSetting> createApnList(Cursor cursor) { 540 ArrayList<ApnSetting> result = new ArrayList<ApnSetting>(); 541 if (cursor.moveToFirst()) { 542 do { 543 String[] types = parseTypes( 544 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); 545 ApnSetting apn = new ApnSetting( 546 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), 547 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), 548 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), 549 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), 550 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)), 551 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), 552 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)), 553 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)), 554 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), 555 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), 556 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), 557 types); 558 result.add(apn); 559 } while (cursor.moveToNext()); 560 } 561 return result; 562 } 563 564 private PdpConnection findFreePdp() { 565 for (DataConnection conn : pdpList) { 566 PdpConnection pdp = (PdpConnection) conn; 567 if (pdp.getState() == DataConnection.State.INACTIVE) { 568 return pdp; 569 } 570 } 571 return null; 572 } 573 574 private boolean setupData(String reason) { 575 ApnSetting apn; 576 PdpConnection pdp; 577 578 apn = getNextApn(); 579 if (apn == null) return false; 580 pdp = findFreePdp(); 581 if (pdp == null) { 582 if (DBG) log("setupData: No free PdpConnection found!"); 583 return false; 584 } 585 mActiveApn = apn; 586 mActivePdp = pdp; 587 588 Message msg = obtainMessage(); 589 msg.what = EVENT_DATA_SETUP_COMPLETE; 590 msg.obj = reason; 591 pdp.connect(apn, msg); 592 593 setState(State.INITING); 594 phone.notifyDataConnection(reason); 595 return true; 596 } 597 598 protected String getInterfaceName(String apnType) { 599 if (mActivePdp != null 600 && (apnType == null || mActiveApn.canHandleType(apnType))) { 601 return mActivePdp.getInterface(); 602 } 603 return null; 604 } 605 606 protected String getIpAddress(String apnType) { 607 if (mActivePdp != null 608 && (apnType == null || mActiveApn.canHandleType(apnType))) { 609 return mActivePdp.getIpAddress(); 610 } 611 return null; 612 } 613 614 public String getGateway(String apnType) { 615 if (mActivePdp != null 616 && (apnType == null || mActiveApn.canHandleType(apnType))) { 617 return mActivePdp.getGatewayAddress(); 618 } 619 return null; 620 } 621 622 protected String[] getDnsServers(String apnType) { 623 if (mActivePdp != null 624 && (apnType == null || mActiveApn.canHandleType(apnType))) { 625 return mActivePdp.getDnsServers(); 626 } 627 return null; 628 } 629 630 private boolean 631 pdpStatesHasCID (ArrayList<DataCallState> states, int cid) { 632 for (int i = 0, s = states.size() ; i < s ; i++) { 633 if (states.get(i).cid == cid) return true; 634 } 635 636 return false; 637 } 638 639 private boolean 640 pdpStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { 641 for (int i = 0, s = states.size() ; i < s ; i++) { 642 if ((states.get(i).cid == cid) && (states.get(i).active != 0)) { 643 return true; 644 } 645 } 646 647 return false; 648 } 649 650 /** 651 * Handles changes to the APN database. 652 */ 653 private void onApnChanged() { 654 boolean isConnected; 655 656 isConnected = (state != State.IDLE && state != State.FAILED); 657 658 // The "current" may no longer be valid. MMS depends on this to send properly. 659 mGsmPhone.updateCurrentCarrierInProvider(); 660 661 // TODO: It'd be nice to only do this if the changed entrie(s) 662 // match the current operator. 663 createAllApnList(); 664 if (state != State.DISCONNECTING) { 665 cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); 666 if (!isConnected) { 667 // reset reconnect timer 668 mRetryMgr.resetRetryCount(); 669 mReregisterOnReconnectFailure = false; 670 trySetupData(Phone.REASON_APN_CHANGED); 671 } 672 } 673 } 674 675 /** 676 * @param explicitPoll if true, indicates that *we* polled for this 677 * update while state == CONNECTED rather than having it delivered 678 * via an unsolicited response (which could have happened at any 679 * previous state 680 */ 681 protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { 682 ArrayList<DataCallState> pdpStates; 683 684 pdpStates = (ArrayList<DataCallState>)(ar.result); 685 686 if (ar.exception != null) { 687 // This is probably "radio not available" or something 688 // of that sort. If so, the whole connection is going 689 // to come down soon anyway 690 return; 691 } 692 693 if (state == State.CONNECTED) { 694 // The way things are supposed to work, the PDP list 695 // should not contain the CID after it disconnects. 696 // However, the way things really work, sometimes the PDP 697 // context is still listed with active = false, which 698 // makes it hard to distinguish an activating context from 699 // an activated-and-then deactivated one. 700 if (!pdpStatesHasCID(pdpStates, cidActive)) { 701 // It looks like the PDP context has deactivated. 702 // Tear everything down and try to reconnect. 703 704 Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); 705 706 // Add an event log when the network drops PDP 707 int cid = -1; 708 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); 709 if (loc != null) cid = loc.getCid(); 710 EventLog.List val = new EventLog.List(cid, 711 TelephonyManager.getDefault().getNetworkType()); 712 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); 713 714 cleanUpConnection(true, null); 715 return; 716 } else if (!pdpStatesHasActiveCID(pdpStates, cidActive)) { 717 // Here, we only consider this authoritative if we asked for the 718 // PDP list. If it was an unsolicited response, we poll again 719 // to make sure everyone agrees on the initial state. 720 721 if (!explicitPoll) { 722 // We think it disconnected but aren't sure...poll from our side 723 phone.mCM.getPDPContextList( 724 this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); 725 } else { 726 Log.i(LOG_TAG, "PDP connection has dropped (active=false case). " 727 + " Reconnecting"); 728 729 // Log the network drop on the event log. 730 int cid = -1; 731 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); 732 if (loc != null) cid = loc.getCid(); 733 EventLog.List val = new EventLog.List(cid, 734 TelephonyManager.getDefault().getNetworkType()); 735 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); 736 737 cleanUpConnection(true, null); 738 } 739 } 740 } 741 } 742 743 private void notifyDefaultData(String reason) { 744 setupDnsProperties(); 745 setState(State.CONNECTED); 746 phone.notifyDataConnection(reason); 747 startNetStatPoll(); 748 // reset reconnect timer 749 mRetryMgr.resetRetryCount(); 750 mReregisterOnReconnectFailure = false; 751 } 752 753 private void setupDnsProperties() { 754 int mypid = android.os.Process.myPid(); 755 String[] servers = getDnsServers(null); 756 String propName; 757 String propVal; 758 int count; 759 760 count = 0; 761 for (int i = 0; i < servers.length; i++) { 762 String serverAddr = servers[i]; 763 if (!TextUtils.equals(serverAddr, "0.0.0.0")) { 764 SystemProperties.set("net.dns" + (i+1) + "." + mypid, serverAddr); 765 count++; 766 } 767 } 768 for (int i = count+1; i <= 4; i++) { 769 propName = "net.dns" + i + "." + mypid; 770 propVal = SystemProperties.get(propName); 771 if (propVal.length() != 0) { 772 SystemProperties.set(propName, ""); 773 } 774 } 775 /* 776 * Bump the property that tells the name resolver library 777 * to reread the DNS server list from the properties. 778 */ 779 propVal = SystemProperties.get("net.dnschange"); 780 if (propVal.length() != 0) { 781 try { 782 int n = Integer.parseInt(propVal); 783 SystemProperties.set("net.dnschange", "" + (n+1)); 784 } catch (NumberFormatException e) { 785 } 786 } 787 } 788 789 /** 790 * This is a kludge to deal with the fact that 791 * the PDP state change notification doesn't always work 792 * with certain RIL impl's/basebands 793 * 794 */ 795 private void startPeriodicPdpPoll() { 796 removeMessages(EVENT_POLL_PDP); 797 798 sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); 799 } 800 801 private void resetPollStats() { 802 txPkts = -1; 803 rxPkts = -1; 804 sentSinceLastRecv = 0; 805 netStatPollPeriod = POLL_NETSTAT_MILLIS; 806 mNoRecvPollCount = 0; 807 } 808 809 private void doRecovery() { 810 if (state == State.CONNECTED) { 811 int maxPdpReset = Settings.Gservices.getInt(mResolver, 812 Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, 813 DEFAULT_MAX_PDP_RESET_FAIL); 814 if (mPdpResetCount < maxPdpReset) { 815 mPdpResetCount++; 816 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, sentSinceLastRecv); 817 cleanUpConnection(true, Phone.REASON_PDP_RESET); 818 } else { 819 mPdpResetCount = 0; 820 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); 821 mGsmPhone.mSST.reRegisterNetwork(null); 822 } 823 // TODO: Add increasingly drastic recovery steps, eg, 824 // reset the radio, reset the device. 825 } 826 } 827 828 protected void startNetStatPoll() { 829 if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { 830 Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); 831 resetPollStats(); 832 netStatPollEnabled = true; 833 mPollNetStat.run(); 834 } 835 } 836 837 protected void stopNetStatPoll() { 838 netStatPollEnabled = false; 839 removeCallbacks(mPollNetStat); 840 Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); 841 } 842 843 protected void restartRadio() { 844 Log.d(LOG_TAG, "************TURN OFF RADIO**************"); 845 cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); 846 phone.mCM.setRadioPower(false, null); 847 /* Note: no need to call setRadioPower(true). Assuming the desired 848 * radio power state is still ON (as tracked by ServiceStateTracker), 849 * ServiceStateTracker will call setRadioPower when it receives the 850 * RADIO_STATE_CHANGED notification for the power off. And if the 851 * desired power state has changed in the interim, we don't want to 852 * override it with an unconditional power on. 853 */ 854 855 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0")); 856 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); 857 } 858 859 private Runnable mPollNetStat = new Runnable() 860 { 861 862 public void run() { 863 long sent, received; 864 long preTxPkts = -1, preRxPkts = -1; 865 866 Activity newActivity; 867 868 preTxPkts = txPkts; 869 preRxPkts = rxPkts; 870 871 try { 872 txPkts = netstat.getMobileTxPackets(); 873 rxPkts = netstat.getMobileRxPackets(); 874 } catch (RemoteException e) { 875 txPkts = 0; 876 rxPkts = 0; 877 } 878 879 //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); 880 881 if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { 882 sent = txPkts - preTxPkts; 883 received = rxPkts - preRxPkts; 884 885 if ( sent > 0 && received > 0 ) { 886 sentSinceLastRecv = 0; 887 newActivity = Activity.DATAINANDOUT; 888 mPdpResetCount = 0; 889 } else if (sent > 0 && received == 0) { 890 if (phone.getState() == Phone.State.IDLE) { 891 sentSinceLastRecv += sent; 892 } else { 893 sentSinceLastRecv = 0; 894 } 895 newActivity = Activity.DATAOUT; 896 } else if (sent == 0 && received > 0) { 897 sentSinceLastRecv = 0; 898 newActivity = Activity.DATAIN; 899 mPdpResetCount = 0; 900 } else if (sent == 0 && received == 0) { 901 newActivity = Activity.NONE; 902 } else { 903 sentSinceLastRecv = 0; 904 newActivity = Activity.NONE; 905 } 906 907 if (activity != newActivity && mIsScreenOn) { 908 activity = newActivity; 909 phone.notifyDataActivity(); 910 } 911 } 912 913 int watchdogTrigger = Settings.Gservices.getInt(mResolver, 914 Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, 915 NUMBER_SENT_PACKETS_OF_HANG); 916 917 if (sentSinceLastRecv >= watchdogTrigger) { 918 // we already have NUMBER_SENT_PACKETS sent without ack 919 if (mNoRecvPollCount == 0) { 920 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED, 921 sentSinceLastRecv); 922 } 923 924 int noRecvPollLimit = Settings.Gservices.getInt(mResolver, 925 Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT); 926 927 if (mNoRecvPollCount < noRecvPollLimit) { 928 // It's possible the PDP context went down and we weren't notified. 929 // Start polling the context list in an attempt to recover. 930 if (DBG) log("no DATAIN in a while; polling PDP"); 931 phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); 932 933 mNoRecvPollCount++; 934 935 // Slow down the poll interval to let things happen 936 netStatPollPeriod = Settings.Gservices.getInt(mResolver, 937 Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, 938 POLL_NETSTAT_SLOW_MILLIS); 939 } else { 940 if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + 941 " pkts since last received"); 942 // We've exceeded the threshold. Run ping test as a final check; 943 // it will proceed with recovery if ping fails. 944 stopNetStatPoll(); 945 Thread pingTest = new Thread() { 946 public void run() { 947 runPingTest(); 948 } 949 }; 950 mPingTestActive = true; 951 pingTest.start(); 952 } 953 } else { 954 mNoRecvPollCount = 0; 955 if (mIsScreenOn) { 956 netStatPollPeriod = Settings.Gservices.getInt(mResolver, 957 Settings.Gservices.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); 958 } else { 959 netStatPollPeriod = Settings.Gservices.getInt(mResolver, 960 Settings.Gservices.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, 961 POLL_NETSTAT_SCREEN_OFF_MILLIS); 962 } 963 } 964 965 if (netStatPollEnabled) { 966 mDataConnectionTracker.postDelayed(this, netStatPollPeriod); 967 } 968 } 969 }; 970 971 private void runPingTest () { 972 int status = -1; 973 try { 974 String address = Settings.Gservices.getString(mResolver, 975 Settings.Gservices.PDP_WATCHDOG_PING_ADDRESS); 976 int deadline = Settings.Gservices.getInt(mResolver, 977 Settings.Gservices.PDP_WATCHDOG_PING_DEADLINE, DEFAULT_PING_DEADLINE); 978 if (DBG) log("pinging " + address + " for " + deadline + "s"); 979 if (address != null && !NULL_IP.equals(address)) { 980 Process p = Runtime.getRuntime() 981 .exec("ping -c 1 -i 1 -w "+ deadline + " " + address); 982 status = p.waitFor(); 983 } 984 } catch (IOException e) { 985 Log.w(LOG_TAG, "ping failed: IOException"); 986 } catch (Exception e) { 987 Log.w(LOG_TAG, "exception trying to ping"); 988 } 989 990 if (status == 0) { 991 // ping succeeded. False alarm. Reset netStatPoll. 992 // ("-1" for this event indicates a false alarm) 993 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, -1); 994 mPdpResetCount = 0; 995 sendMessage(obtainMessage(EVENT_START_NETSTAT_POLL)); 996 } else { 997 // ping failed. Proceed with recovery. 998 sendMessage(obtainMessage(EVENT_START_RECOVERY)); 999 } 1000 } 1001 1002 /** 1003 * Returns true if the last fail cause is something that 1004 * seems like it deserves an error notification. 1005 * Transient errors are ignored 1006 */ 1007 private boolean shouldPostNotification(PdpConnection.FailCause cause) { 1008 boolean shouldPost = true; 1009 // TODO CHECK 1010 // if (dataLink != null) { 1011 // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED; 1012 //} 1013 return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN); 1014 } 1015 1016 /** 1017 * Return true if data connection need to be setup after disconnected due to 1018 * reason. 1019 * 1020 * @param reason the reason why data is disconnected 1021 * @return true if try setup data connection is need for this reason 1022 */ 1023 private boolean retryAfterDisconnected(String reason) { 1024 boolean retry = true; 1025 1026 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) { 1027 retry = false; 1028 } 1029 return retry; 1030 } 1031 1032 private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { 1033 if (state == State.FAILED) { 1034 if (!mRetryMgr.isRetryNeeded()) { 1035 if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { 1036 // if no more retries on a secondary APN attempt, tell the world and revert. 1037 phone.notifyDataConnection(Phone.REASON_APN_FAILED); 1038 onEnableApn(apnTypeToId(mRequestedApnType), APN_DISABLED); 1039 return; 1040 } 1041 if (mReregisterOnReconnectFailure) { 1042 // We've re-registerd once now just retry forever. 1043 mRetryMgr.retryForeverUsingLastTimeout(); 1044 } else { 1045 // Try to re-register to the network. 1046 Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); 1047 mReregisterOnReconnectFailure = true; 1048 mGsmPhone.mSST.reRegisterNetwork(null); 1049 mRetryMgr.resetRetryCount(); 1050 return; 1051 } 1052 } 1053 1054 int nextReconnectDelay = mRetryMgr.getRetryTimer(); 1055 Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " 1056 + (nextReconnectDelay / 1000) + "s"); 1057 1058 AlarmManager am = 1059 (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); 1060 Intent intent = new Intent(INTENT_RECONNECT_ALARM); 1061 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); 1062 mReconnectIntent = PendingIntent.getBroadcast( 1063 phone.getContext(), 0, intent, 0); 1064 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1065 SystemClock.elapsedRealtime() + nextReconnectDelay, 1066 mReconnectIntent); 1067 1068 mRetryMgr.increaseRetryCount(); 1069 1070 if (!shouldPostNotification(lastFailCauseCode)) { 1071 Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " 1072 + "-- likely transient error"); 1073 } else { 1074 notifyNoData(lastFailCauseCode); 1075 } 1076 } 1077 } 1078 1079 private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) { 1080 setState(State.FAILED); 1081 } 1082 1083 protected void onRecordsLoaded() { 1084 createAllApnList(); 1085 if (state == State.FAILED) { 1086 cleanUpConnection(false, null); 1087 } 1088 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); 1089 } 1090 1091 @Override 1092 protected void onEnableNewApn() { 1093 // change our retry manager to use the appropriate numbers for the new APN 1094 if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { 1095 mRetryMgr = mDefaultRetryManager; 1096 } else { 1097 mRetryMgr = mSecondaryRetryManager; 1098 } 1099 mRetryMgr.resetRetryCount(); 1100 1101 // TODO: To support simultaneous PDP contexts, this should really only call 1102 // cleanUpConnection if it needs to free up a PdpConnection. 1103 cleanUpConnection(true, Phone.REASON_APN_SWITCHED); 1104 } 1105 1106 protected boolean onTrySetupData(String reason) { 1107 return trySetupData(reason); 1108 } 1109 1110 @Override 1111 protected void onRoamingOff() { 1112 trySetupData(Phone.REASON_ROAMING_OFF); 1113 } 1114 1115 @Override 1116 protected void onRoamingOn() { 1117 if (getDataOnRoamingEnabled()) { 1118 trySetupData(Phone.REASON_ROAMING_ON); 1119 } else { 1120 if (DBG) log("Tear down data connection on roaming."); 1121 cleanUpConnection(true, Phone.REASON_ROAMING_ON); 1122 } 1123 } 1124 1125 protected void onRadioAvailable() { 1126 if (phone.getSimulatedRadioControl() != null) { 1127 // Assume data is connected on the simulator 1128 // FIXME this can be improved 1129 setState(State.CONNECTED); 1130 phone.notifyDataConnection(null); 1131 1132 Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); 1133 } 1134 1135 if (state != State.IDLE) { 1136 cleanUpConnection(true, null); 1137 } 1138 } 1139 1140 protected void onRadioOffOrNotAvailable() { 1141 // Make sure our reconnect delay starts at the initial value 1142 // next time the radio comes on 1143 mRetryMgr.resetRetryCount(); 1144 mReregisterOnReconnectFailure = false; 1145 1146 if (phone.getSimulatedRadioControl() != null) { 1147 // Assume data is connected on the simulator 1148 // FIXME this can be improved 1149 Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); 1150 } else { 1151 if (DBG) log("Radio is off and clean up all connection"); 1152 // TODO: Should we reset mRequestedApnType to "default"? 1153 cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); 1154 } 1155 } 1156 1157 protected void onDataSetupComplete(AsyncResult ar) { 1158 String reason = null; 1159 if (ar.userObj instanceof String) { 1160 reason = (String) ar.userObj; 1161 } 1162 1163 if (ar.exception == null) { 1164 // everything is setup 1165 if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { 1166 SystemProperties.set("gsm.defaultpdpcontext.active", "true"); 1167 if (canSetPreferApn && preferredApn == null) { 1168 Log.d(LOG_TAG, "PREFERED APN is null"); 1169 preferredApn = mActiveApn; 1170 setPreferredApn(preferredApn.id); 1171 } 1172 } else { 1173 SystemProperties.set("gsm.defaultpdpcontext.active", "false"); 1174 } 1175 notifyDefaultData(reason); 1176 1177 // TODO: For simultaneous PDP support, we need to build another 1178 // trigger another TRY_SETUP_DATA for the next APN type. (Note 1179 // that the existing connection may service that type, in which 1180 // case we should try the next type, etc. 1181 } else { 1182 PdpConnection.FailCause cause; 1183 cause = (PdpConnection.FailCause) (ar.result); 1184 if(DBG) log("PDP setup failed " + cause); 1185 // Log this failure to the Event Logs. 1186 if (cause.isEventLoggable()) { 1187 int cid = -1; 1188 GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); 1189 if (loc != null) cid = loc.getCid(); 1190 1191 EventLog.List val = new EventLog.List( 1192 cause.ordinal(), cid, 1193 TelephonyManager.getDefault().getNetworkType()); 1194 EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); 1195 } 1196 1197 // No try for permanent failure 1198 if (cause.isPermanentFail()) { 1199 notifyNoData(cause); 1200 if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { 1201 phone.notifyDataConnection(Phone.REASON_APN_FAILED); 1202 onEnableApn(apnTypeToId(mRequestedApnType), APN_DISABLED); 1203 } 1204 return; 1205 } 1206 1207 waitingApns.remove(0); 1208 if (waitingApns.isEmpty()) { 1209 // No more to try, start delayed retry 1210 startDelayedRetry(cause, reason); 1211 } else { 1212 // we still have more apns to try 1213 setState(State.SCANNING); 1214 // Wait a bit before trying the next APN, so that 1215 // we're not tying up the RIL command channel 1216 sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS); 1217 } 1218 } 1219 } 1220 1221 protected void onDisconnectDone(AsyncResult ar) { 1222 String reason = null; 1223 if(DBG) log("EVENT_DISCONNECT_DONE"); 1224 if (ar.userObj instanceof String) { 1225 reason = (String) ar.userObj; 1226 } 1227 setState(State.IDLE); 1228 phone.notifyDataConnection(reason); 1229 mActiveApn = null; 1230 if (retryAfterDisconnected(reason)) { 1231 trySetupData(reason); 1232 } 1233 } 1234 1235 protected void onPollPdp() { 1236 if (state == State.CONNECTED) { 1237 // only poll when connected 1238 phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); 1239 sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); 1240 } 1241 } 1242 1243 protected void onVoiceCallStarted() { 1244 if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { 1245 stopNetStatPoll(); 1246 phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); 1247 } 1248 } 1249 1250 protected void onVoiceCallEnded() { 1251 if (state == State.CONNECTED) { 1252 if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) { 1253 startNetStatPoll(); 1254 phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); 1255 } else { 1256 // clean slate after call end. 1257 resetPollStats(); 1258 } 1259 } else { 1260 // reset reconnect timer 1261 mRetryMgr.resetRetryCount(); 1262 mReregisterOnReconnectFailure = false; 1263 // in case data setup was attempted when we were on a voice call 1264 trySetupData(Phone.REASON_VOICE_CALL_ENDED); 1265 } 1266 } 1267 1268 protected void onCleanUpConnection(boolean tearDown, String reason) { 1269 cleanUpConnection(tearDown, reason); 1270 } 1271 1272 /** 1273 * Based on the sim operator numeric, create a list for all possible pdps 1274 * with all apns associated with that pdp 1275 * 1276 * 1277 */ 1278 private void createAllApnList() { 1279 allApns = new ArrayList<ApnSetting>(); 1280 String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); 1281 1282 if (operator != null) { 1283 String selection = "numeric = '" + operator + "'"; 1284 1285 Cursor cursor = phone.getContext().getContentResolver().query( 1286 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 1287 1288 if (cursor != null) { 1289 if (cursor.getCount() > 0) { 1290 allApns = createApnList(cursor); 1291 // TODO: Figure out where this fits in. This basically just 1292 // writes the pap-secrets file. No longer tied to PdpConnection 1293 // object. Not used on current platform (no ppp). 1294 //PdpConnection pdp = pdpList.get(pdp_name); 1295 //if (pdp != null && pdp.dataLink != null) { 1296 // pdp.dataLink.setPasswordInfo(cursor); 1297 //} 1298 } 1299 cursor.close(); 1300 } 1301 } 1302 1303 if (allApns.isEmpty()) { 1304 if (DBG) log("No APN found for carrier: " + operator); 1305 preferredApn = null; 1306 notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); 1307 } else { 1308 preferredApn = getPreferredApn(); 1309 Log.d(LOG_TAG, "Get PreferredAPN"); 1310 if (preferredApn != null && !preferredApn.numeric.equals(operator)) { 1311 preferredApn = null; 1312 setPreferredApn(-1); 1313 } 1314 } 1315 } 1316 1317 private void createAllPdpList() { 1318 pdpList = new ArrayList<DataConnection>(); 1319 DataConnection pdp; 1320 1321 for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { 1322 pdp = new PdpConnection(mGsmPhone); 1323 pdpList.add(pdp); 1324 } 1325 } 1326 1327 private void destroyAllPdpList() { 1328 if(pdpList != null) { 1329 PdpConnection pdp; 1330 pdpList.removeAll(pdpList); 1331 } 1332 } 1333 1334 /** 1335 * 1336 * @return waitingApns list to be used to create PDP 1337 * error when waitingApns.isEmpty() 1338 */ 1339 private ArrayList<ApnSetting> buildWaitingApns() { 1340 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); 1341 String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); 1342 1343 if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { 1344 if (canSetPreferApn && preferredApn != null) { 1345 Log.i(LOG_TAG, "Preferred APN:" + operator + ":" 1346 + preferredApn.numeric + ":" + preferredApn); 1347 if (preferredApn.numeric.equals(operator)) { 1348 Log.i(LOG_TAG, "Waiting APN set to preferred APN"); 1349 apnList.add(preferredApn); 1350 return apnList; 1351 } else { 1352 setPreferredApn(-1); 1353 preferredApn = null; 1354 } 1355 } 1356 } 1357 1358 if (allApns != null) { 1359 for (ApnSetting apn : allApns) { 1360 if (apn.canHandleType(mRequestedApnType)) { 1361 apnList.add(apn); 1362 } 1363 } 1364 } 1365 return apnList; 1366 } 1367 1368 /** 1369 * Get next apn in waitingApns 1370 * @return the first apn found in waitingApns, null if none 1371 */ 1372 private ApnSetting getNextApn() { 1373 ArrayList<ApnSetting> list = waitingApns; 1374 ApnSetting apn = null; 1375 1376 if (list != null) { 1377 if (!list.isEmpty()) { 1378 apn = list.get(0); 1379 } 1380 } 1381 return apn; 1382 } 1383 1384 private String apnListToString (ArrayList<ApnSetting> apns) { 1385 StringBuilder result = new StringBuilder(); 1386 for (int i = 0, size = apns.size(); i < size; i++) { 1387 result.append('[') 1388 .append(apns.get(i).toString()) 1389 .append(']'); 1390 } 1391 return result.toString(); 1392 } 1393 1394 private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { 1395 notifyNoData(cause); 1396 reconnectAfterFail(cause, reason); 1397 } 1398 1399 private void setPreferredApn(int pos) { 1400 if (!canSetPreferApn) { 1401 return; 1402 } 1403 1404 ContentResolver resolver = phone.getContext().getContentResolver(); 1405 resolver.delete(PREFERAPN_URI, null, null); 1406 1407 if (pos >= 0) { 1408 ContentValues values = new ContentValues(); 1409 values.put(APN_ID, pos); 1410 resolver.insert(PREFERAPN_URI, values); 1411 } 1412 } 1413 1414 private ApnSetting getPreferredApn() { 1415 if (allApns.isEmpty()) { 1416 return null; 1417 } 1418 1419 Cursor cursor = phone.getContext().getContentResolver().query( 1420 PREFERAPN_URI, new String[] { "_id", "name", "apn" }, 1421 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 1422 1423 if (cursor != null) { 1424 canSetPreferApn = true; 1425 } else { 1426 canSetPreferApn = false; 1427 } 1428 1429 if (canSetPreferApn && cursor.getCount() > 0) { 1430 int pos; 1431 cursor.moveToFirst(); 1432 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); 1433 for(ApnSetting p:allApns) { 1434 if (p.id == pos && p.canHandleType(mRequestedApnType)) { 1435 cursor.close(); 1436 return p; 1437 } 1438 } 1439 } 1440 1441 if (cursor != null) { 1442 cursor.close(); 1443 } 1444 1445 return null; 1446 } 1447 1448 public void handleMessage (Message msg) { 1449 if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); 1450 switch (msg.what) { 1451 case EVENT_RECORDS_LOADED: 1452 onRecordsLoaded(); 1453 break; 1454 1455 case EVENT_GPRS_DETACHED: 1456 onGprsDetached(); 1457 break; 1458 1459 case EVENT_GPRS_ATTACHED: 1460 onGprsAttached(); 1461 break; 1462 1463 case EVENT_DATA_STATE_CHANGED: 1464 onPdpStateChanged((AsyncResult) msg.obj, false); 1465 break; 1466 1467 case EVENT_GET_PDP_LIST_COMPLETE: 1468 onPdpStateChanged((AsyncResult) msg.obj, true); 1469 break; 1470 1471 case EVENT_POLL_PDP: 1472 onPollPdp(); 1473 break; 1474 1475 case EVENT_START_NETSTAT_POLL: 1476 mPingTestActive = false; 1477 startNetStatPoll(); 1478 break; 1479 1480 case EVENT_START_RECOVERY: 1481 mPingTestActive = false; 1482 doRecovery(); 1483 break; 1484 1485 case EVENT_APN_CHANGED: 1486 onApnChanged(); 1487 break; 1488 1489 case EVENT_PS_RESTRICT_ENABLED: 1490 /** 1491 * We don't need to explicitly to tear down the PDP context 1492 * when PS restricted is enabled. The base band will deactive 1493 * PDP context and notify us with PDP_CONTEXT_CHANGED. 1494 * But we should stop the network polling and prevent reset PDP. 1495 */ 1496 Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); 1497 stopNetStatPoll(); 1498 mIsPsRestricted = true; 1499 break; 1500 1501 case EVENT_PS_RESTRICT_DISABLED: 1502 /** 1503 * When PS restrict is removed, we need setup PDP connection if 1504 * PDP connection is down. 1505 */ 1506 Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); 1507 mIsPsRestricted = false; 1508 if (state == State.CONNECTED) { 1509 startNetStatPoll(); 1510 } else { 1511 if (state == State.FAILED) { 1512 cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); 1513 mRetryMgr.resetRetryCount(); 1514 mReregisterOnReconnectFailure = false; 1515 } 1516 trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); 1517 } 1518 break; 1519 1520 default: 1521 // handle the message in the super class DataConnectionTracker 1522 super.handleMessage(msg); 1523 break; 1524 } 1525 } 1526 1527 protected void log(String s) { 1528 Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); 1529 } 1530 1531} 1532