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