1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.gsm; 18 19 import android.app.AlarmManager; 20 import android.app.PendingIntent; 21 import android.content.ContentResolver; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.database.ContentObserver; 27 import android.database.Cursor; 28 import android.net.ConnectivityManager; 29 import android.net.LinkAddress; 30 import android.net.LinkCapabilities; 31 import android.net.LinkProperties; 32 import android.net.LinkProperties.CompareResult; 33 import android.net.NetworkConfig; 34 import android.net.NetworkUtils; 35 import android.net.ProxyProperties; 36 import android.net.TrafficStats; 37 import android.net.Uri; 38 import android.os.AsyncResult; 39 import android.os.Message; 40 import android.os.SystemClock; 41 import android.os.SystemProperties; 42 import android.provider.Settings; 43 import android.provider.Telephony; 44 import android.telephony.CellLocation; 45 import android.telephony.ServiceState; 46 import android.telephony.TelephonyManager; 47 import android.telephony.cdma.CdmaCellLocation; 48 import android.telephony.gsm.GsmCellLocation; 49 import android.text.TextUtils; 50 import android.util.EventLog; 51 import android.util.Log; 52 53 import com.android.internal.telephony.ApnContext; 54 import com.android.internal.telephony.ApnSetting; 55 import com.android.internal.telephony.DataCallState; 56 import com.android.internal.telephony.DataConnection; 57 import com.android.internal.telephony.DataConnection.FailCause; 58 import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult; 59 import com.android.internal.telephony.DataConnectionAc; 60 import com.android.internal.telephony.DataConnectionTracker; 61 import com.android.internal.telephony.EventLogTags; 62 import com.android.internal.telephony.Phone; 63 import com.android.internal.telephony.PhoneBase; 64 import com.android.internal.telephony.RILConstants; 65 import com.android.internal.telephony.RetryManager; 66 import com.android.internal.util.AsyncChannel; 67 68 import java.util.ArrayList; 69 import java.util.Collection; 70 import java.util.HashMap; 71 import java.util.List; 72 import java.util.concurrent.ConcurrentHashMap; 73 74 /** 75 * {@hide} 76 */ 77 public final class GsmDataConnectionTracker extends DataConnectionTracker { 78 protected final String LOG_TAG = "GSM"; 79 80 /** 81 * Handles changes to the APN db. 82 */ 83 private class ApnChangeObserver extends ContentObserver { 84 public ApnChangeObserver () { 85 super(mDataConnectionTracker); 86 } 87 88 @Override 89 public void onChange(boolean selfChange) { 90 sendMessage(obtainMessage(EVENT_APN_CHANGED)); 91 } 92 } 93 94 //***** Instance Variables 95 96 private boolean mReregisterOnReconnectFailure = false; 97 private ContentResolver mResolver; 98 99 // Recovery action taken in case of data stall 100 class RecoveryAction { 101 public static final int GET_DATA_CALL_LIST = 0; 102 public static final int CLEANUP = 1; 103 public static final int REREGISTER = 2; 104 public static final int RADIO_RESTART = 3; 105 public static final int RADIO_RESTART_WITH_PROP = 4; 106 } 107 public int getRecoveryAction() { 108 int action = Settings.System.getInt(mPhone.getContext().getContentResolver(), 109 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST); 110 if (VDBG) log("getRecoveryAction: " + action); 111 return action; 112 } 113 public void putRecoveryAction(int action) { 114 Settings.System.putInt(mPhone.getContext().getContentResolver(), 115 "radio.data.stall.recovery.action", action); 116 if (VDBG) log("putRecoveryAction: " + action); 117 } 118 119 //***** Constants 120 121 private static final int POLL_PDP_MILLIS = 5 * 1000; 122 123 private static final String INTENT_RECONNECT_ALARM = 124 "com.android.internal.telephony.gprs-reconnect"; 125 private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "type"; 126 127 private static final String INTENT_DATA_STALL_ALARM = 128 "com.android.internal.telephony.gprs-data-stall"; 129 130 static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); 131 static final String APN_ID = "apn_id"; 132 private boolean canSetPreferApn = false; 133 134 @Override 135 protected void onActionIntentReconnectAlarm(Intent intent) { 136 if (DBG) log("GPRS reconnect alarm. Previous state was " + mState); 137 138 String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); 139 int connectionId = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, -1); 140 141 DataConnectionAc dcac= mDataConnectionAsyncChannels.get(connectionId); 142 143 if (dcac != null) { 144 for (ApnContext apnContext : dcac.getApnListSync()) { 145 apnContext.setReason(reason); 146 if (apnContext.getState() == State.FAILED) { 147 apnContext.setState(State.IDLE); 148 } 149 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext)); 150 } 151 // Alram had expired. Clear pending intent recorded on the DataConnection. 152 dcac.setReconnectIntentSync(null); 153 } 154 } 155 156 /** Watches for changes to the APN db. */ 157 private ApnChangeObserver mApnObserver; 158 159 //***** Constructor 160 161 public GsmDataConnectionTracker(PhoneBase p) { 162 super(p); 163 164 p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); 165 p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 166 p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); 167 p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null); 168 p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); 169 p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); 170 p.getServiceStateTracker().registerForDataConnectionAttached(this, 171 EVENT_DATA_CONNECTION_ATTACHED, null); 172 p.getServiceStateTracker().registerForDataConnectionDetached(this, 173 EVENT_DATA_CONNECTION_DETACHED, null); 174 p.getServiceStateTracker().registerForRoamingOn(this, EVENT_ROAMING_ON, null); 175 p.getServiceStateTracker().registerForRoamingOff(this, EVENT_ROAMING_OFF, null); 176 p.getServiceStateTracker().registerForPsRestrictedEnabled(this, 177 EVENT_PS_RESTRICT_ENABLED, null); 178 p.getServiceStateTracker().registerForPsRestrictedDisabled(this, 179 EVENT_PS_RESTRICT_DISABLED, null); 180 181 // install reconnect intent filter for this data connection. 182 IntentFilter filter = new IntentFilter(); 183 filter.addAction(INTENT_DATA_STALL_ALARM); 184 p.getContext().registerReceiver(mIntentReceiver, filter, null, p); 185 186 mDataConnectionTracker = this; 187 mResolver = mPhone.getContext().getContentResolver(); 188 189 mApnObserver = new ApnChangeObserver(); 190 p.getContext().getContentResolver().registerContentObserver( 191 Telephony.Carriers.CONTENT_URI, true, mApnObserver); 192 193 mApnContexts = new ConcurrentHashMap<String, ApnContext>(); 194 initApnContextsAndDataConnection(); 195 broadcastMessenger(); 196 } 197 198 @Override 199 public void dispose() { 200 cleanUpAllConnections(false, null); 201 202 super.dispose(); 203 204 //Unregister for all events 205 mPhone.mCM.unregisterForAvailable(this); 206 mPhone.mCM.unregisterForOffOrNotAvailable(this); 207 mPhone.mIccRecords.unregisterForRecordsLoaded(this); 208 mPhone.mCM.unregisterForDataNetworkStateChanged(this); 209 mPhone.getCallTracker().unregisterForVoiceCallEnded(this); 210 mPhone.getCallTracker().unregisterForVoiceCallStarted(this); 211 mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this); 212 mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this); 213 mPhone.getServiceStateTracker().unregisterForRoamingOn(this); 214 mPhone.getServiceStateTracker().unregisterForRoamingOff(this); 215 mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); 216 mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); 217 218 mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver); 219 mApnContexts.clear(); 220 221 destroyDataConnections(); 222 } 223 224 @Override 225 public boolean isApnTypeActive(String type) { 226 ApnContext apnContext = mApnContexts.get(type); 227 if (apnContext == null) return false; 228 229 return (apnContext.getDataConnection() != null); 230 } 231 232 @Override 233 protected boolean isDataPossible(String apnType) { 234 ApnContext apnContext = mApnContexts.get(apnType); 235 if (apnContext == null) { 236 return false; 237 } 238 boolean apnContextIsEnabled = apnContext.isEnabled(); 239 State apnContextState = apnContext.getState(); 240 boolean apnTypePossible = !(apnContextIsEnabled && 241 (apnContextState == State.FAILED)); 242 boolean dataAllowed = isDataAllowed(); 243 boolean possible = dataAllowed && apnTypePossible; 244 245 if (DBG) { 246 log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " + 247 "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s", 248 apnType, possible, dataAllowed, apnTypePossible, 249 apnContextIsEnabled, apnContextState)); 250 } 251 return possible; 252 } 253 254 @Override 255 protected void finalize() { 256 if(DBG) log("finalize"); 257 } 258 259 @Override 260 protected String getActionIntentReconnectAlarm() { 261 return INTENT_RECONNECT_ALARM; 262 } 263 264 @Override 265 protected String getActionIntentDataStallAlarm() { 266 return INTENT_DATA_STALL_ALARM; 267 } 268 269 private ApnContext addApnContext(String type) { 270 ApnContext apnContext = new ApnContext(type, LOG_TAG); 271 apnContext.setDependencyMet(false); 272 mApnContexts.put(type, apnContext); 273 return apnContext; 274 } 275 276 protected void initApnContextsAndDataConnection() { 277 boolean defaultEnabled = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP, true); 278 // Load device network attributes from resources 279 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray( 280 com.android.internal.R.array.networkAttributes); 281 for (String networkConfigString : networkConfigStrings) { 282 NetworkConfig networkConfig = new NetworkConfig(networkConfigString); 283 ApnContext apnContext = null; 284 285 switch (networkConfig.type) { 286 case ConnectivityManager.TYPE_MOBILE: 287 apnContext = addApnContext(Phone.APN_TYPE_DEFAULT); 288 apnContext.setEnabled(defaultEnabled); 289 break; 290 case ConnectivityManager.TYPE_MOBILE_MMS: 291 apnContext = addApnContext(Phone.APN_TYPE_MMS); 292 break; 293 case ConnectivityManager.TYPE_MOBILE_SUPL: 294 apnContext = addApnContext(Phone.APN_TYPE_SUPL); 295 break; 296 case ConnectivityManager.TYPE_MOBILE_DUN: 297 apnContext = addApnContext(Phone.APN_TYPE_DUN); 298 break; 299 case ConnectivityManager.TYPE_MOBILE_HIPRI: 300 apnContext = addApnContext(Phone.APN_TYPE_HIPRI); 301 ApnContext defaultContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT); 302 if (defaultContext != null) { 303 applyNewState(apnContext, apnContext.isEnabled(), 304 defaultContext.getDependencyMet()); 305 } else { 306 // the default will set the hipri dep-met when it is created 307 } 308 continue; 309 case ConnectivityManager.TYPE_MOBILE_FOTA: 310 apnContext = addApnContext(Phone.APN_TYPE_FOTA); 311 break; 312 case ConnectivityManager.TYPE_MOBILE_IMS: 313 apnContext = addApnContext(Phone.APN_TYPE_IMS); 314 break; 315 case ConnectivityManager.TYPE_MOBILE_CBS: 316 apnContext = addApnContext(Phone.APN_TYPE_CBS); 317 break; 318 default: 319 // skip unknown types 320 continue; 321 } 322 if (apnContext != null) { 323 // set the prop, but also apply the newly set enabled and dependency values 324 onSetDependencyMet(apnContext.getApnType(), networkConfig.dependencyMet); 325 } 326 } 327 } 328 329 @Override 330 protected LinkProperties getLinkProperties(String apnType) { 331 ApnContext apnContext = mApnContexts.get(apnType); 332 if (apnContext != null) { 333 DataConnectionAc dcac = apnContext.getDataConnectionAc(); 334 if (dcac != null) { 335 if (DBG) log("return link properites for " + apnType); 336 return dcac.getLinkPropertiesSync(); 337 } 338 } 339 if (DBG) log("return new LinkProperties"); 340 return new LinkProperties(); 341 } 342 343 @Override 344 protected LinkCapabilities getLinkCapabilities(String apnType) { 345 ApnContext apnContext = mApnContexts.get(apnType); 346 if (apnContext!=null) { 347 DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc(); 348 if (dataConnectionAc != null) { 349 if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType); 350 return dataConnectionAc.getLinkCapabilitiesSync(); 351 } 352 } 353 if (DBG) log("return new LinkCapabilities"); 354 return new LinkCapabilities(); 355 } 356 357 @Override 358 // Return all active apn types 359 public String[] getActiveApnTypes() { 360 if (DBG) log("get all active apn types"); 361 ArrayList<String> result = new ArrayList<String>(); 362 363 for (ApnContext apnContext : mApnContexts.values()) { 364 if (apnContext.isReady()) { 365 result.add(apnContext.getApnType()); 366 } 367 } 368 369 return (String[])result.toArray(new String[0]); 370 } 371 372 @Override 373 // Return active apn of specific apn type 374 public String getActiveApnString(String apnType) { 375 if (DBG) log( "get active apn string for type:" + apnType); 376 ApnContext apnContext = mApnContexts.get(apnType); 377 if (apnContext != null) { 378 ApnSetting apnSetting = apnContext.getApnSetting(); 379 if (apnSetting != null) { 380 return apnSetting.apn; 381 } 382 } 383 return null; 384 } 385 386 @Override 387 public boolean isApnTypeEnabled(String apnType) { 388 ApnContext apnContext = mApnContexts.get(apnType); 389 if (apnContext == null) { 390 return false; 391 } 392 return apnContext.isEnabled(); 393 } 394 395 @Override 396 protected void setState(State s) { 397 if (DBG) log("setState should not be used in GSM" + s); 398 } 399 400 // Return state of specific apn type 401 @Override 402 public State getState(String apnType) { 403 ApnContext apnContext = mApnContexts.get(apnType); 404 if (apnContext != null) { 405 return apnContext.getState(); 406 } 407 return State.FAILED; 408 } 409 410 // Return state of overall 411 public State getOverallState() { 412 boolean isConnecting = false; 413 boolean isFailed = true; // All enabled Apns should be FAILED. 414 boolean isAnyEnabled = false; 415 416 for (ApnContext apnContext : mApnContexts.values()) { 417 if (apnContext.isEnabled()) { 418 isAnyEnabled = true; 419 switch (apnContext.getState()) { 420 case CONNECTED: 421 case DISCONNECTING: 422 if (DBG) log("overall state is CONNECTED"); 423 return State.CONNECTED; 424 case CONNECTING: 425 case INITING: 426 isConnecting = true; 427 isFailed = false; 428 break; 429 case IDLE: 430 case SCANNING: 431 isFailed = false; 432 break; 433 } 434 } 435 } 436 437 if (!isAnyEnabled) { // Nothing enabled. return IDLE. 438 if (DBG) log( "overall state is IDLE"); 439 return State.IDLE; 440 } 441 442 if (isConnecting) { 443 if (DBG) log( "overall state is CONNECTING"); 444 return State.CONNECTING; 445 } else if (!isFailed) { 446 if (DBG) log( "overall state is IDLE"); 447 return State.IDLE; 448 } else { 449 if (DBG) log( "overall state is FAILED"); 450 return State.FAILED; 451 } 452 } 453 454 /** 455 * Ensure that we are connected to an APN of the specified type. 456 * 457 * @param type the APN type 458 * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or 459 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a 460 * broadcast will be sent by the ConnectivityManager when a 461 * connection to the APN has been established. 462 */ 463 @Override 464 public synchronized int enableApnType(String apnType) { 465 ApnContext apnContext = mApnContexts.get(apnType); 466 if (apnContext == null || !isApnTypeAvailable(apnType)) { 467 if (DBG) log("enableApnType: " + apnType + " is type not available"); 468 return Phone.APN_TYPE_NOT_AVAILABLE; 469 } 470 471 // If already active, return 472 if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")"); 473 474 if (apnContext.getState() == State.CONNECTED) { 475 if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE"); 476 return Phone.APN_ALREADY_ACTIVE; 477 } 478 setEnabled(apnTypeToId(apnType), true); 479 if (DBG) { 480 log("enableApnType: new apn request for type " + apnType + 481 " return APN_REQUEST_STARTED"); 482 } 483 return Phone.APN_REQUEST_STARTED; 484 } 485 486 // A new APN has gone active and needs to send events to catch up with the 487 // current condition 488 private void notifyApnIdUpToCurrent(String reason, ApnContext apnContext, String type) { 489 switch (apnContext.getState()) { 490 case IDLE: 491 case INITING: 492 break; 493 case CONNECTING: 494 case SCANNING: 495 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING); 496 break; 497 case CONNECTED: 498 case DISCONNECTING: 499 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING); 500 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTED); 501 break; 502 } 503 } 504 505 @Override 506 public synchronized int disableApnType(String type) { 507 if (DBG) log("disableApnType:" + type); 508 ApnContext apnContext = mApnContexts.get(type); 509 510 if (apnContext != null) { 511 setEnabled(apnTypeToId(type), false); 512 if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) { 513 if (DBG) log("diableApnType: return APN_REQUEST_STARTED"); 514 return Phone.APN_REQUEST_STARTED; 515 } else { 516 if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE"); 517 return Phone.APN_ALREADY_INACTIVE; 518 } 519 520 } else { 521 if (DBG) { 522 log("disableApnType: no apn context was found, return APN_REQUEST_FAILED"); 523 } 524 return Phone.APN_REQUEST_FAILED; 525 } 526 } 527 528 @Override 529 protected boolean isApnTypeAvailable(String type) { 530 if (type.equals(Phone.APN_TYPE_DUN) && fetchDunApn() != null) { 531 return true; 532 } 533 534 if (mAllApns != null) { 535 for (ApnSetting apn : mAllApns) { 536 if (apn.canHandleType(type)) { 537 return true; 538 } 539 } 540 } 541 return false; 542 } 543 544 /** 545 * Report on whether data connectivity is enabled for any APN. 546 * @return {@code false} if data connectivity has been explicitly disabled, 547 * {@code true} otherwise. 548 */ 549 @Override 550 public boolean getAnyDataEnabled() { 551 synchronized (mDataEnabledLock) { 552 if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false; 553 for (ApnContext apnContext : mApnContexts.values()) { 554 // Make sure we dont have a context that going down 555 // and is explicitly disabled. 556 if (isDataAllowed(apnContext)) { 557 return true; 558 } 559 } 560 return false; 561 } 562 } 563 564 private boolean isDataAllowed(ApnContext apnContext) { 565 return apnContext.isReady() && isDataAllowed(); 566 } 567 568 //****** Called from ServiceStateTracker 569 /** 570 * Invoked when ServiceStateTracker observes a transition from GPRS 571 * attach to detach. 572 */ 573 protected void onDataConnectionDetached() { 574 /* 575 * We presently believe it is unnecessary to tear down the PDP context 576 * when GPRS detaches, but we should stop the network polling. 577 */ 578 if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); 579 stopNetStatPoll(); 580 stopDataStallAlarm(); 581 notifyDataConnection(Phone.REASON_DATA_DETACHED); 582 } 583 584 private void onDataConnectionAttached() { 585 if (DBG) log("onDataConnectionAttached"); 586 if (getOverallState() == State.CONNECTED) { 587 if (DBG) log("onDataConnectionAttached: start polling notify attached"); 588 startNetStatPoll(); 589 startDataStallAlarm(); 590 notifyDataConnection(Phone.REASON_DATA_ATTACHED); 591 } else { 592 // update APN availability so that APN can be enabled. 593 notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED); 594 } 595 596 setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED); 597 } 598 599 @Override 600 protected boolean isDataAllowed() { 601 final boolean internalDataEnabled; 602 synchronized (mDataEnabledLock) { 603 internalDataEnabled = mInternalDataEnabled; 604 } 605 606 int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState(); 607 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); 608 609 boolean allowed = 610 (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && 611 mPhone.mIccRecords.getRecordsLoaded() && 612 (mPhone.getState() == Phone.State.IDLE || 613 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) && 614 internalDataEnabled && 615 (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) && 616 !mIsPsRestricted && 617 desiredPowerState; 618 if (!allowed && DBG) { 619 String reason = ""; 620 if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { 621 reason += " - gprs= " + gprsState; 622 } 623 if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded"; 624 if (mPhone.getState() != Phone.State.IDLE && 625 !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 626 reason += " - PhoneState= " + mPhone.getState(); 627 reason += " - Concurrent voice and data not allowed"; 628 } 629 if (!internalDataEnabled) reason += " - mInternalDataEnabled= false"; 630 if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) { 631 reason += " - Roaming and data roaming not enabled"; 632 } 633 if (mIsPsRestricted) reason += " - mIsPsRestricted= true"; 634 if (!desiredPowerState) reason += " - desiredPowerState= false"; 635 if (DBG) log("isDataAllowed: not allowed due to" + reason); 636 } 637 return allowed; 638 } 639 640 private void setupDataOnReadyApns(String reason) { 641 // Stop reconnect alarms on all data connections pending 642 // retry. Reset ApnContext state to IDLE. 643 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { 644 if (dcac.getReconnectIntentSync() != null) { 645 cancelReconnectAlarm(dcac); 646 } 647 // update retry config for existing calls to match up 648 // ones for the new RAT. 649 if (dcac.dataConnection != null) { 650 Collection<ApnContext> apns = dcac.getApnListSync(); 651 652 boolean hasDefault = false; 653 for (ApnContext apnContext : apns) { 654 if (apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) { 655 hasDefault = true; 656 break; 657 } 658 } 659 configureRetry(dcac.dataConnection, hasDefault); 660 } 661 } 662 663 // Only check for default APN state 664 for (ApnContext apnContext : mApnContexts.values()) { 665 if (apnContext.getState() == State.FAILED) { 666 // By this time, alarms for all failed Apns 667 // should be stopped if any. 668 // Make sure to set the state back to IDLE 669 // so that setup data can happen. 670 apnContext.setState(State.IDLE); 671 } 672 if (apnContext.isReady()) { 673 if (apnContext.getState() == State.IDLE) { 674 apnContext.setReason(reason); 675 trySetupData(apnContext); 676 } 677 } 678 } 679 } 680 681 private boolean trySetupData(String reason, String type) { 682 if (DBG) { 683 log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason) 684 + " isPsRestricted=" + mIsPsRestricted); 685 } 686 687 if (type == null) { 688 type = Phone.APN_TYPE_DEFAULT; 689 } 690 691 ApnContext apnContext = mApnContexts.get(type); 692 693 if (apnContext == null ){ 694 if (DBG) log("trySetupData new apn context for type:" + type); 695 apnContext = new ApnContext(type, LOG_TAG); 696 mApnContexts.put(type, apnContext); 697 } 698 apnContext.setReason(reason); 699 700 return trySetupData(apnContext); 701 } 702 703 private boolean trySetupData(ApnContext apnContext) { 704 if (DBG) { 705 log("trySetupData for type:" + apnContext.getApnType() + 706 " due to " + apnContext.getReason()); 707 log("trySetupData with mIsPsRestricted=" + mIsPsRestricted); 708 } 709 710 if (mPhone.getSimulatedRadioControl() != null) { 711 // Assume data is connected on the simulator 712 // FIXME this can be improved 713 apnContext.setState(State.CONNECTED); 714 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 715 716 log("trySetupData: (fix?) We're on the simulator; assuming data is connected"); 717 return true; 718 } 719 720 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); 721 722 if ((apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING) && 723 isDataAllowed(apnContext) && getAnyDataEnabled() && !isEmergency()) { 724 725 if (apnContext.getState() == State.IDLE) { 726 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType()); 727 if (waitingApns.isEmpty()) { 728 if (DBG) log("trySetupData: No APN found"); 729 notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext); 730 notifyOffApnsOfAvailability(apnContext.getReason()); 731 return false; 732 } else { 733 apnContext.setWaitingApns(waitingApns); 734 if (DBG) { 735 log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns)); 736 } 737 } 738 } 739 740 if (DBG) { 741 log ("Setup watingApns : " + apnListToString(apnContext.getWaitingApns())); 742 } 743 // apnContext.setReason(apnContext.getReason()); 744 boolean retValue = setupData(apnContext); 745 notifyOffApnsOfAvailability(apnContext.getReason()); 746 return retValue; 747 } else { 748 // TODO: check the condition. 749 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT) 750 && (apnContext.getState() == State.IDLE 751 || apnContext.getState() == State.SCANNING)) 752 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 753 notifyOffApnsOfAvailability(apnContext.getReason()); 754 return false; 755 } 756 } 757 758 @Override 759 // Disabled apn's still need avail/unavail notificiations - send them out 760 protected void notifyOffApnsOfAvailability(String reason) { 761 for (ApnContext apnContext : mApnContexts.values()) { 762 if (!apnContext.isReady()) { 763 if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType()); 764 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 765 apnContext.getApnType(), 766 Phone.DataState.DISCONNECTED); 767 } else { 768 if (DBG) { 769 log("notifyOffApnsOfAvailability skipped apn due to isReady==false: " + 770 apnContext.toString()); 771 } 772 } 773 } 774 } 775 776 /** 777 * If tearDown is true, this only tears down a CONNECTED session. Presently, 778 * there is no mechanism for abandoning an INITING/CONNECTING session, 779 * but would likely involve cancelling pending async requests or 780 * setting a flag or new state to ignore them when they came in 781 * @param tearDown true if the underlying GsmDataConnection should be 782 * disconnected. 783 * @param reason reason for the clean up. 784 */ 785 protected void cleanUpAllConnections(boolean tearDown, String reason) { 786 if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason); 787 788 for (ApnContext apnContext : mApnContexts.values()) { 789 apnContext.setReason(reason); 790 cleanUpConnection(tearDown, apnContext); 791 } 792 793 stopNetStatPoll(); 794 stopDataStallAlarm(); 795 796 // TODO: Do we need mRequestedApnType? 797 mRequestedApnType = Phone.APN_TYPE_DEFAULT; 798 } 799 800 /** 801 * Cleanup all connections. 802 * 803 * TODO: Cleanup only a specified connection passed as a parameter. 804 * Also, make sure when you clean up a conn, if it is last apply 805 * logic as though it is cleanupAllConnections 806 * 807 * @param tearDown true if the underlying DataConnection should be disconnected. 808 * @param reason for the clean up. 809 */ 810 811 @Override 812 protected void onCleanUpAllConnections(String cause) { 813 cleanUpAllConnections(true, cause); 814 } 815 816 private void cleanUpConnection(boolean tearDown, ApnContext apnContext) { 817 818 if (apnContext == null) { 819 if (DBG) log("cleanUpConnection: apn context is null"); 820 return; 821 } 822 823 if (DBG) { 824 log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason()); 825 } 826 DataConnectionAc dcac = apnContext.getDataConnectionAc(); 827 if (tearDown) { 828 if (apnContext.isDisconnected()) { 829 // The request is tearDown and but ApnContext is not connected. 830 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. 831 apnContext.setState(State.IDLE); 832 if (!apnContext.isReady()) { 833 apnContext.setDataConnection(null); 834 apnContext.setDataConnectionAc(null); 835 } 836 } else { 837 // Connection is still there. Try to clean up. 838 if (dcac != null) { 839 if (apnContext.getState() != State.DISCONNECTING) { 840 if (DBG) log("cleanUpConnection: tearing down"); 841 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext); 842 apnContext.getDataConnection().tearDown(apnContext.getReason(), msg); 843 apnContext.setState(State.DISCONNECTING); 844 } 845 } else { 846 // apn is connected but no reference to dcac. 847 // Should not be happen, but reset the state in case. 848 apnContext.setState(State.IDLE); 849 mPhone.notifyDataConnection(apnContext.getReason(), 850 apnContext.getApnType()); 851 } 852 } 853 } else { 854 // force clean up the data connection. 855 if (dcac != null) dcac.resetSync(); 856 apnContext.setState(State.IDLE); 857 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 858 apnContext.setDataConnection(null); 859 apnContext.setDataConnectionAc(null); 860 } 861 862 // make sure reconnection alarm is cleaned up if there is no ApnContext 863 // associated to the connection. 864 if (dcac != null) { 865 Collection<ApnContext> apnList = dcac.getApnListSync(); 866 if (apnList.isEmpty()) { 867 cancelReconnectAlarm(dcac); 868 } 869 } 870 } 871 872 /** 873 * Cancels the alarm associated with DCAC. 874 * 875 * @param DataConnectionAc on which the alarm should be stopped. 876 */ 877 private void cancelReconnectAlarm(DataConnectionAc dcac) { 878 if (dcac == null) return; 879 880 PendingIntent intent = dcac.getReconnectIntentSync(); 881 882 if (intent != null) { 883 AlarmManager am = 884 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 885 am.cancel(intent); 886 dcac.setReconnectIntentSync(null); 887 } 888 } 889 890 /** 891 * @param types comma delimited list of APN types 892 * @return array of APN types 893 */ 894 private String[] parseTypes(String types) { 895 String[] result; 896 // If unset, set to DEFAULT. 897 if (types == null || types.equals("")) { 898 result = new String[1]; 899 result[0] = Phone.APN_TYPE_ALL; 900 } else { 901 result = types.split(","); 902 } 903 return result; 904 } 905 906 private ArrayList<ApnSetting> createApnList(Cursor cursor) { 907 ArrayList<ApnSetting> result = new ArrayList<ApnSetting>(); 908 if (cursor.moveToFirst()) { 909 do { 910 String[] types = parseTypes( 911 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); 912 ApnSetting apn = new ApnSetting( 913 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), 914 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), 915 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), 916 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), 917 NetworkUtils.trimV4AddrZeros( 918 cursor.getString( 919 cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), 920 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), 921 NetworkUtils.trimV4AddrZeros( 922 cursor.getString( 923 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), 924 NetworkUtils.trimV4AddrZeros( 925 cursor.getString( 926 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), 927 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), 928 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), 929 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), 930 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), 931 types, 932 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), 933 cursor.getString(cursor.getColumnIndexOrThrow( 934 Telephony.Carriers.ROAMING_PROTOCOL)), 935 cursor.getInt(cursor.getColumnIndexOrThrow( 936 Telephony.Carriers.CARRIER_ENABLED)) == 1, 937 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER))); 938 result.add(apn); 939 } while (cursor.moveToNext()); 940 } 941 if (DBG) log("createApnList: X result=" + result); 942 return result; 943 } 944 945 private boolean dataConnectionNotInUse(DataConnectionAc dcac) { 946 for (ApnContext apnContext : mApnContexts.values()) { 947 if (apnContext.getDataConnectionAc() == dcac) return false; 948 } 949 return true; 950 } 951 952 private GsmDataConnection findFreeDataConnection() { 953 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { 954 if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) { 955 log("findFreeDataConnection: found free GsmDataConnection"); 956 return (GsmDataConnection) dcac.dataConnection; 957 } 958 } 959 log("findFreeDataConnection: NO free GsmDataConnection"); 960 return null; 961 } 962 963 protected GsmDataConnection findReadyDataConnection(ApnSetting apn) { 964 if (DBG) 965 log("findReadyDataConnection: apn string <" + 966 (apn!=null?(apn.toString()):"null") +">"); 967 if (apn == null) { 968 return null; 969 } 970 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { 971 ApnSetting apnSetting = dcac.getApnSettingSync(); 972 if (DBG) { 973 log("findReadyDataConnection: dc apn string <" + 974 (apnSetting != null ? (apnSetting.toString()) : "null") + ">"); 975 } 976 if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) { 977 return (GsmDataConnection) dcac.dataConnection; 978 } 979 } 980 return null; 981 } 982 983 984 private boolean setupData(ApnContext apnContext) { 985 if (DBG) log("setupData: apnContext=" + apnContext); 986 ApnSetting apn; 987 GsmDataConnection dc; 988 989 int profileId = getApnProfileID(apnContext.getApnType()); 990 apn = apnContext.getNextWaitingApn(); 991 if (apn == null) { 992 if (DBG) log("setupData: return for no apn found!"); 993 return false; 994 } 995 996 // First, check to see if ApnContext already has DC. 997 // This could happen if the retries are currently engaged. 998 dc = (GsmDataConnection)apnContext.getDataConnection(); 999 1000 if (dc == null) { 1001 1002 dc = (GsmDataConnection) checkForConnectionForApnContext(apnContext); 1003 1004 if (dc == null) { 1005 dc = findReadyDataConnection(apn); 1006 } 1007 1008 if (dc == null) { 1009 if (DBG) log("setupData: No ready GsmDataConnection found!"); 1010 // TODO: When allocating you are mapping type to id. If more than 1 free, 1011 // then could findFreeDataConnection get the wrong one?? 1012 dc = findFreeDataConnection(); 1013 } 1014 1015 if (dc == null) { 1016 dc = createDataConnection(); 1017 } 1018 1019 if (dc == null) { 1020 if (DBG) log("setupData: No free GsmDataConnection found!"); 1021 return false; 1022 } 1023 1024 DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId()); 1025 dc.setProfileId( profileId ); 1026 dc.setActiveApnType(apnContext.getApnType()); 1027 int refCount = dcac.getRefCountSync(); 1028 if (DBG) log("setupData: init dc and apnContext refCount=" + refCount); 1029 1030 // configure retry count if no other Apn is using the same connection. 1031 if (refCount == 0) { 1032 configureRetry(dc, apn.canHandleType(Phone.APN_TYPE_DEFAULT)); 1033 } 1034 apnContext.setDataConnectionAc(dcac); 1035 apnContext.setDataConnection(dc); 1036 } 1037 1038 apnContext.setApnSetting(apn); 1039 apnContext.setState(State.INITING); 1040 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1041 // If reconnect alarm is active on this DataConnection, wait for the alarm being 1042 // fired so that we don't disruppt data retry pattern engaged. 1043 if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) { 1044 if (DBG) log("setupData: data reconnection pending"); 1045 apnContext.setState(State.FAILED); 1046 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1047 return true; 1048 } 1049 1050 Message msg = obtainMessage(); 1051 msg.what = EVENT_DATA_SETUP_COMPLETE; 1052 msg.obj = apnContext; 1053 dc.bringUp(msg, apn); 1054 1055 if (DBG) log("setupData: initing!"); 1056 return true; 1057 } 1058 1059 /** 1060 * Handles changes to the APN database. 1061 */ 1062 private void onApnChanged() { 1063 State overallState = getOverallState(); 1064 boolean isDisconnected = (overallState == State.IDLE || overallState == State.FAILED); 1065 1066 if (mPhone instanceof GSMPhone) { 1067 // The "current" may no longer be valid. MMS depends on this to send properly. TBD 1068 ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); 1069 } 1070 1071 // TODO: It'd be nice to only do this if the changed entrie(s) 1072 // match the current operator. 1073 if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); 1074 createAllApnList(); 1075 cleanUpAllConnections(!isDisconnected, Phone.REASON_APN_CHANGED); 1076 if (isDisconnected) { 1077 setupDataOnReadyApns(Phone.REASON_APN_CHANGED); 1078 } 1079 } 1080 1081 /** 1082 * @param cid Connection id provided from RIL. 1083 * @return DataConnectionAc associated with specified cid. 1084 */ 1085 private DataConnectionAc findDataConnectionAcByCid(int cid) { 1086 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { 1087 if (dcac.getCidSync() == cid) { 1088 return dcac; 1089 } 1090 } 1091 return null; 1092 } 1093 1094 /** 1095 * @param dcacs Collection of DataConnectionAc reported from RIL. 1096 * @return List of ApnContext which is connected, but is not present in 1097 * data connection list reported from RIL. 1098 */ 1099 private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) { 1100 if (dcacs == null) return null; 1101 1102 ArrayList<ApnContext> list = new ArrayList<ApnContext>(); 1103 for (ApnContext apnContext : mApnContexts.values()) { 1104 if (apnContext.getState() == State.CONNECTED) { 1105 boolean found = false; 1106 for (DataConnectionAc dcac : dcacs) { 1107 if (dcac == apnContext.getDataConnectionAc()) { 1108 // ApnContext holds the ref to dcac present in data call list. 1109 found = true; 1110 break; 1111 } 1112 } 1113 if (!found) { 1114 // ApnContext does not have dcac reported in data call list. 1115 // Fetch all the ApnContexts that map to this dcac which are in 1116 // INITING state too. 1117 if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" + 1118 apnContext.toString() + ")"); 1119 if (apnContext.getDataConnectionAc() != null) { 1120 list.addAll(apnContext.getDataConnectionAc().getApnListSync()); 1121 } else { 1122 list.add(apnContext); 1123 } 1124 } 1125 } 1126 } 1127 return list; 1128 } 1129 1130 /** 1131 * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST 1132 * or RIL_UNSOL_DATA_CALL_LIST_CHANGED 1133 */ 1134 private void onDataStateChanged (AsyncResult ar) { 1135 ArrayList<DataCallState> dataCallStates; 1136 1137 if (DBG) log("onDataStateChanged(ar): E"); 1138 dataCallStates = (ArrayList<DataCallState>)(ar.result); 1139 1140 if (ar.exception != null) { 1141 // This is probably "radio not available" or something 1142 // of that sort. If so, the whole connection is going 1143 // to come down soon anyway 1144 if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore"); 1145 return; 1146 } 1147 if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); 1148 1149 // Create a hash map to store the dataCallState of each DataConnectionAc 1150 HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac; 1151 dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>(); 1152 for (DataCallState dataCallState : dataCallStates) { 1153 DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid); 1154 1155 if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac); 1156 } 1157 1158 // A list of apns to cleanup, those that aren't in the list we know we have to cleanup 1159 List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values()); 1160 1161 // Find which connections have changed state and send a notification or cleanup 1162 for (DataCallState newState : dataCallStates) { 1163 DataConnectionAc dcac = dataCallStateToDcac.get(newState); 1164 1165 if (dcac == null) { 1166 loge("onDataStateChanged(ar): No associated DataConnection ignore"); 1167 continue; 1168 } 1169 1170 // The list of apn's associated with this DataConnection 1171 Collection<ApnContext> apns = dcac.getApnListSync(); 1172 1173 // Find which ApnContexts of this DC are in the "Connected/Connecting" state. 1174 ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); 1175 for (ApnContext apnContext : apns) { 1176 if (apnContext.getState() == State.CONNECTED || 1177 apnContext.getState() == State.CONNECTING || 1178 apnContext.getState() == State.INITING) { 1179 connectedApns.add(apnContext); 1180 } 1181 } 1182 if (connectedApns.size() == 0) { 1183 if (DBG) log("onDataStateChanged(ar): no connected apns"); 1184 } else { 1185 // Determine if the connection/apnContext should be cleaned up 1186 // or just a notification should be sent out. 1187 if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid 1188 + " newState=" + newState.toString()); 1189 if (newState.active == 0) { 1190 if (DBG) { 1191 log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns); 1192 } 1193 apnsToCleanup.addAll(connectedApns); 1194 } else { 1195 // Its active so update the DataConnections link properties 1196 UpdateLinkPropertyResult result = 1197 dcac.updateLinkPropertiesDataCallStateSync(newState); 1198 if (result.oldLp.equals(result.newLp)) { 1199 if (DBG) log("onDataStateChanged(ar): no change"); 1200 } else { 1201 if (result.oldLp.isIdenticalInterfaceName(result.newLp)) { 1202 if (! result.oldLp.isIdenticalDnses(result.newLp) || 1203 ! result.oldLp.isIdenticalRoutes(result.newLp) || 1204 ! result.oldLp.isIdenticalHttpProxy(result.newLp) || 1205 ! result.oldLp.isIdenticalAddresses(result.newLp)) { 1206 // If the same address type was removed and added we need to cleanup 1207 CompareResult<LinkAddress> car = 1208 result.oldLp.compareAddresses(result.newLp); 1209 boolean needToClean = false; 1210 for (LinkAddress added : car.added) { 1211 for (LinkAddress removed : car.removed) { 1212 if (NetworkUtils.addressTypeMatches(removed.getAddress(), 1213 added.getAddress())) { 1214 needToClean = true; 1215 break; 1216 } 1217 } 1218 } 1219 if (needToClean) { 1220 if (DBG) { 1221 log("onDataStateChanged(ar): addr change, cleanup apns=" + 1222 connectedApns); 1223 } 1224 apnsToCleanup.addAll(connectedApns); 1225 } else { 1226 if (DBG) log("onDataStateChanged(ar): simple change"); 1227 for (ApnContext apnContext : connectedApns) { 1228 mPhone.notifyDataConnection( 1229 Phone.REASON_LINK_PROPERTIES_CHANGED, 1230 apnContext.getApnType()); 1231 } 1232 } 1233 } else { 1234 if (DBG) { 1235 log("onDataStateChanged(ar): no changes"); 1236 } 1237 } 1238 } else { 1239 if (DBG) { 1240 log("onDataStateChanged(ar): interface change, cleanup apns=" 1241 + connectedApns); 1242 } 1243 apnsToCleanup.addAll(connectedApns); 1244 } 1245 } 1246 } 1247 } 1248 } 1249 1250 if (apnsToCleanup.size() != 0) { 1251 // Add an event log when the network drops PDP 1252 int cid = getCellLocationId(); 1253 EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, 1254 TelephonyManager.getDefault().getNetworkType()); 1255 } 1256 1257 // Cleanup those dropped connections 1258 for (ApnContext apnContext : apnsToCleanup) { 1259 cleanUpConnection(true, apnContext); 1260 } 1261 1262 if (DBG) log("onDataStateChanged(ar): X"); 1263 } 1264 1265 private void notifyDefaultData(ApnContext apnContext) { 1266 if (DBG) { 1267 log("notifyDefaultData: type=" + apnContext.getApnType() 1268 + ", reason:" + apnContext.getReason()); 1269 } 1270 apnContext.setState(State.CONNECTED); 1271 // setState(State.CONNECTED); 1272 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1273 startNetStatPoll(); 1274 startDataStallAlarm(); 1275 // reset reconnect timer 1276 apnContext.getDataConnection().resetRetryCount(); 1277 } 1278 1279 // TODO: For multiple Active APNs not exactly sure how to do this. 1280 protected void gotoIdleAndNotifyDataConnection(String reason) { 1281 if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); 1282 notifyDataConnection(reason); 1283 mActiveApn = null; 1284 } 1285 1286 private void resetPollStats() { 1287 mTxPkts = -1; 1288 mRxPkts = -1; 1289 mNetStatPollPeriod = POLL_NETSTAT_MILLIS; 1290 } 1291 1292 private void doRecovery() { 1293 if (getOverallState() == State.CONNECTED) { 1294 // Go through a series of recovery steps, each action transitions to the next action 1295 int recoveryAction = getRecoveryAction(); 1296 switch (recoveryAction) { 1297 case RecoveryAction.GET_DATA_CALL_LIST: 1298 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, 1299 mSentSinceLastRecv); 1300 if (DBG) log("doRecovery() get data call list"); 1301 mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED)); 1302 putRecoveryAction(RecoveryAction.CLEANUP); 1303 break; 1304 case RecoveryAction.CLEANUP: 1305 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv); 1306 if (DBG) log("doRecovery() cleanup all connections"); 1307 cleanUpAllConnections(true, Phone.REASON_PDP_RESET); 1308 putRecoveryAction(RecoveryAction.REREGISTER); 1309 break; 1310 case RecoveryAction.REREGISTER: 1311 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, 1312 mSentSinceLastRecv); 1313 if (DBG) log("doRecovery() re-register"); 1314 mPhone.getServiceStateTracker().reRegisterNetwork(null); 1315 putRecoveryAction(RecoveryAction.RADIO_RESTART); 1316 break; 1317 case RecoveryAction.RADIO_RESTART: 1318 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, 1319 mSentSinceLastRecv); 1320 if (DBG) log("restarting radio"); 1321 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP); 1322 restartRadio(); 1323 break; 1324 case RecoveryAction.RADIO_RESTART_WITH_PROP: 1325 // This is in case radio restart has not recovered the data. 1326 // It will set an additional "gsm.radioreset" property to tell 1327 // RIL or system to take further action. 1328 // The implementation of hard reset recovery action is up to OEM product. 1329 // Once gsm.radioreset property is consumed, it is expected to set back 1330 // to false by RIL. 1331 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1); 1332 if (DBG) log("restarting radio with gsm.radioreset to true"); 1333 SystemProperties.set("gsm.radioreset", "true"); 1334 // give 1 sec so property change can be notified. 1335 try { 1336 Thread.sleep(1000); 1337 } catch (InterruptedException e) {} 1338 restartRadio(); 1339 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1340 break; 1341 default: 1342 throw new RuntimeException("doRecovery: Invalid recoveryAction=" + 1343 recoveryAction); 1344 } 1345 } 1346 } 1347 1348 @Override 1349 protected void startNetStatPoll() { 1350 if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) { 1351 if (DBG) log("startNetStatPoll"); 1352 resetPollStats(); 1353 mNetStatPollEnabled = true; 1354 mPollNetStat.run(); 1355 } 1356 } 1357 1358 @Override 1359 protected void stopNetStatPoll() { 1360 mNetStatPollEnabled = false; 1361 removeCallbacks(mPollNetStat); 1362 if (DBG) log("stopNetStatPoll"); 1363 } 1364 1365 @Override 1366 protected void restartRadio() { 1367 if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); 1368 cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF); 1369 mPhone.getServiceStateTracker().powerOffRadioSafely(this); 1370 /* Note: no need to call setRadioPower(true). Assuming the desired 1371 * radio power state is still ON (as tracked by ServiceStateTracker), 1372 * ServiceStateTracker will call setRadioPower when it receives the 1373 * RADIO_STATE_CHANGED notification for the power off. And if the 1374 * desired power state has changed in the interim, we don't want to 1375 * override it with an unconditional power on. 1376 */ 1377 1378 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0")); 1379 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); 1380 } 1381 1382 1383 private void updateDataStallInfo() { 1384 long sent, received; 1385 1386 TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); 1387 mDataStallTxRxSum.updateTxRxSum(); 1388 1389 if (VDBG) { 1390 log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + 1391 " preTxRxSum=" + preTxRxSum); 1392 } 1393 1394 sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; 1395 received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; 1396 1397 if (VDBG) { 1398 if (SystemProperties.getBoolean("radio.test.data.stall", false)) { 1399 log("updateDataStallInfo: radio.test.data.stall true received = 0;"); 1400 received = 0; 1401 } 1402 } 1403 if ( sent > 0 && received > 0 ) { 1404 if (VDBG) log("updateDataStallInfo: IN/OUT"); 1405 mSentSinceLastRecv = 0; 1406 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1407 } else if (sent > 0 && received == 0) { 1408 if (mPhone.getState() == Phone.State.IDLE) { 1409 mSentSinceLastRecv += sent; 1410 } else { 1411 mSentSinceLastRecv = 0; 1412 } 1413 if (DBG) { 1414 log("updateDataStallInfo: OUT sent=" + sent + 1415 " mSentSinceLastRecv=" + mSentSinceLastRecv); 1416 } 1417 } else if (sent == 0 && received > 0) { 1418 if (VDBG) log("updateDataStallInfo: IN"); 1419 mSentSinceLastRecv = 0; 1420 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1421 } else { 1422 if (VDBG) log("updateDataStallInfo: NONE"); 1423 } 1424 } 1425 1426 @Override 1427 protected void onDataStallAlarm(int tag) { 1428 if (mDataStallAlarmTag != tag) { 1429 if (DBG) { 1430 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); 1431 } 1432 return; 1433 } 1434 updateDataStallInfo(); 1435 1436 int hangWatchdogTrigger = Settings.Secure.getInt(mResolver, 1437 Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, 1438 NUMBER_SENT_PACKETS_OF_HANG); 1439 1440 if (mSentSinceLastRecv >= hangWatchdogTrigger) { 1441 if (DBG) { 1442 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction()); 1443 } 1444 sendMessage(obtainMessage(EVENT_DO_RECOVERY)); 1445 } else { 1446 if (VDBG) { 1447 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + 1448 " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); 1449 } 1450 } 1451 startDataStallAlarm(); 1452 } 1453 1454 1455 private void updateDataActivity() { 1456 long sent, received; 1457 1458 Activity newActivity; 1459 1460 TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); 1461 TxRxSum curTxRxSum = new TxRxSum(); 1462 curTxRxSum.updateTxRxSum(); 1463 mTxPkts = curTxRxSum.txPkts; 1464 mRxPkts = curTxRxSum.rxPkts; 1465 1466 if (VDBG) { 1467 log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); 1468 } 1469 1470 if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { 1471 sent = mTxPkts - preTxRxSum.txPkts; 1472 received = mRxPkts - preTxRxSum.rxPkts; 1473 1474 if (VDBG) log("updateDataActivity: sent=" + sent + " received=" + received); 1475 if ( sent > 0 && received > 0 ) { 1476 newActivity = Activity.DATAINANDOUT; 1477 } else if (sent > 0 && received == 0) { 1478 newActivity = Activity.DATAOUT; 1479 } else if (sent == 0 && received > 0) { 1480 newActivity = Activity.DATAIN; 1481 } else { 1482 newActivity = Activity.NONE; 1483 } 1484 1485 if (mActivity != newActivity && mIsScreenOn) { 1486 if (VDBG) log("updateDataActivity: newActivity=" + newActivity); 1487 mActivity = newActivity; 1488 mPhone.notifyDataActivity(); 1489 } 1490 } 1491 } 1492 1493 private Runnable mPollNetStat = new Runnable() 1494 { 1495 @Override 1496 public void run() { 1497 updateDataActivity(); 1498 1499 if (mIsScreenOn) { 1500 mNetStatPollPeriod = Settings.Secure.getInt(mResolver, 1501 Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); 1502 } else { 1503 mNetStatPollPeriod = Settings.Secure.getInt(mResolver, 1504 Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, 1505 POLL_NETSTAT_SCREEN_OFF_MILLIS); 1506 } 1507 1508 if (mNetStatPollEnabled) { 1509 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); 1510 } 1511 } 1512 }; 1513 1514 /** 1515 * Returns true if the last fail cause is something that 1516 * seems like it deserves an error notification. 1517 * Transient errors are ignored 1518 */ 1519 private boolean shouldPostNotification(GsmDataConnection.FailCause cause) { 1520 return (cause != GsmDataConnection.FailCause.UNKNOWN); 1521 } 1522 1523 /** 1524 * Return true if data connection need to be setup after disconnected due to 1525 * reason. 1526 * 1527 * @param reason the reason why data is disconnected 1528 * @return true if try setup data connection is need for this reason 1529 */ 1530 private boolean retryAfterDisconnected(String reason) { 1531 boolean retry = true; 1532 1533 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) { 1534 retry = false; 1535 } 1536 return retry; 1537 } 1538 1539 private void reconnectAfterFail(FailCause lastFailCauseCode, 1540 ApnContext apnContext, int retryOverride) { 1541 if (apnContext == null) { 1542 loge("reconnectAfterFail: apnContext == null, impossible"); 1543 return; 1544 } 1545 if ((apnContext.getState() == State.FAILED) && 1546 (apnContext.getDataConnection() != null)) { 1547 if (!apnContext.getDataConnection().isRetryNeeded()) { 1548 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) { 1549 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType()); 1550 return; 1551 } 1552 if (mReregisterOnReconnectFailure) { 1553 // We've re-registerd once now just retry forever. 1554 apnContext.getDataConnection().retryForeverUsingLastTimeout(); 1555 } else { 1556 // Try to Re-register to the network. 1557 if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network"); 1558 mReregisterOnReconnectFailure = true; 1559 mPhone.getServiceStateTracker().reRegisterNetwork(null); 1560 apnContext.getDataConnection().resetRetryCount(); 1561 return; 1562 } 1563 } 1564 1565 // If retry needs to be backed off for specific case (determined by RIL/Modem) 1566 // use the specified timer instead of pre-configured retry pattern. 1567 int nextReconnectDelay = retryOverride; 1568 if (nextReconnectDelay < 0) { 1569 nextReconnectDelay = apnContext.getDataConnection().getRetryTimer(); 1570 apnContext.getDataConnection().increaseRetryCount(); 1571 } 1572 startAlarmForReconnect(nextReconnectDelay, apnContext); 1573 1574 if (!shouldPostNotification(lastFailCauseCode)) { 1575 if (DBG) { 1576 log("reconnectAfterFail: NOT Posting GPRS Unavailable notification " 1577 + "-- likely transient error"); 1578 } 1579 } else { 1580 notifyNoData(lastFailCauseCode, apnContext); 1581 } 1582 } 1583 } 1584 1585 private void startAlarmForReconnect(int delay, ApnContext apnContext) { 1586 1587 if (DBG) { 1588 log("Schedule alarm for reconnect: activate failed. Scheduling next attempt for " 1589 + (delay / 1000) + "s"); 1590 } 1591 1592 DataConnectionAc dcac = apnContext.getDataConnectionAc(); 1593 1594 if ((dcac == null) || (dcac.dataConnection == null)) { 1595 // should not happen, but just in case. 1596 loge("null dcac or dc."); 1597 return; 1598 } 1599 1600 AlarmManager am = 1601 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1602 1603 Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' + 1604 dcac.dataConnection.getDataConnectionId()); 1605 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); 1606 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, 1607 dcac.dataConnection.getDataConnectionId()); 1608 1609 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, 1610 intent, 0); 1611 dcac.setReconnectIntentSync(alarmIntent); 1612 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1613 SystemClock.elapsedRealtime() + delay, alarmIntent); 1614 1615 } 1616 1617 private void startDataStallAlarm() { 1618 int delayInMs = Settings.Secure.getInt(mResolver, 1619 Settings.Secure.DATA_STALL_ALARM_DELAY_IN_MS, 1620 DATA_STALL_ALARM_DELAY_IN_MS_DEFAULT); 1621 mDataStallAlarmTag += 1; 1622 if (DBG) { 1623 log("startDataStallAlarm: tag=" + mDataStallAlarmTag + 1624 " delay=" + (delayInMs / 1000) + "s"); 1625 } 1626 AlarmManager am = 1627 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1628 1629 Intent intent = new Intent(INTENT_DATA_STALL_ALARM); 1630 intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag); 1631 mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, 1632 PendingIntent.FLAG_UPDATE_CURRENT); 1633 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1634 SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); 1635 } 1636 1637 private void stopDataStallAlarm() { 1638 AlarmManager am = 1639 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1640 1641 if (DBG) { 1642 log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + 1643 " mDataStallAlarmIntent=" + mDataStallAlarmIntent); 1644 } 1645 mDataStallAlarmTag += 1; 1646 if (mDataStallAlarmIntent != null) { 1647 am.cancel(mDataStallAlarmIntent); 1648 mDataStallAlarmIntent = null; 1649 } 1650 } 1651 1652 private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode, 1653 ApnContext apnContext) { 1654 if (DBG) log( "notifyNoData: type=" + apnContext.getApnType()); 1655 apnContext.setState(State.FAILED); 1656 if (lastFailCauseCode.isPermanentFail() 1657 && (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) { 1658 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 1659 } 1660 } 1661 1662 private void onRecordsLoaded() { 1663 if (DBG) log("onRecordsLoaded: createAllApnList"); 1664 createAllApnList(); 1665 if (mPhone.mCM.getRadioState().isOn()) { 1666 if (DBG) log("onRecordsLoaded: notifying data availability"); 1667 notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); 1668 } 1669 setupDataOnReadyApns(Phone.REASON_SIM_LOADED); 1670 } 1671 1672 @Override 1673 protected void onSetDependencyMet(String apnType, boolean met) { 1674 // don't allow users to tweak hipri to work around default dependency not met 1675 if (Phone.APN_TYPE_HIPRI.equals(apnType)) return; 1676 1677 ApnContext apnContext = mApnContexts.get(apnType); 1678 if (apnContext == null) { 1679 loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" + 1680 apnType + ", " + met + ")"); 1681 return; 1682 } 1683 applyNewState(apnContext, apnContext.isEnabled(), met); 1684 if (Phone.APN_TYPE_DEFAULT.equals(apnType)) { 1685 // tie actions on default to similar actions on HIPRI regarding dependencyMet 1686 apnContext = mApnContexts.get(Phone.APN_TYPE_HIPRI); 1687 if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met); 1688 } 1689 } 1690 1691 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) { 1692 boolean cleanup = false; 1693 boolean trySetup = false; 1694 if (DBG) { 1695 log("applyNewState(" + apnContext.getApnType() + ", " + enabled + 1696 "(" + apnContext.isEnabled() + "), " + met + "(" + 1697 apnContext.getDependencyMet() +"))"); 1698 } 1699 if (apnContext.isReady()) { 1700 if (enabled && met) return; 1701 if (!enabled) { 1702 apnContext.setReason(Phone.REASON_DATA_DISABLED); 1703 } else { 1704 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); 1705 } 1706 cleanup = true; 1707 } else { 1708 if (enabled && met) { 1709 if (apnContext.isEnabled()) { 1710 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); 1711 } else { 1712 apnContext.setReason(Phone.REASON_DATA_ENABLED); 1713 } 1714 if (apnContext.getState() == State.FAILED) { 1715 apnContext.setState(State.IDLE); 1716 } 1717 trySetup = true; 1718 } 1719 } 1720 apnContext.setEnabled(enabled); 1721 apnContext.setDependencyMet(met); 1722 if (cleanup) cleanUpConnection(true, apnContext); 1723 if (trySetup) trySetupData(apnContext); 1724 } 1725 1726 private DataConnection checkForConnectionForApnContext(ApnContext apnContext) { 1727 // Loop through all apnContexts looking for one with a conn that satisfies this apnType 1728 String apnType = apnContext.getApnType(); 1729 ApnSetting dunSetting = null; 1730 1731 if (Phone.APN_TYPE_DUN.equals(apnType)) { 1732 dunSetting = fetchDunApn(); 1733 } 1734 1735 for (ApnContext c : mApnContexts.values()) { 1736 DataConnection conn = c.getDataConnection(); 1737 if (conn != null) { 1738 ApnSetting apnSetting = c.getApnSetting(); 1739 if (dunSetting != null) { 1740 if (dunSetting.equals(apnSetting)) { 1741 if (DBG) { 1742 log("checkForConnectionForApnContext: apnContext=" + apnContext + 1743 " found conn=" + conn); 1744 } 1745 return conn; 1746 } 1747 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) { 1748 if (DBG) { 1749 log("checkForConnectionForApnContext: apnContext=" + apnContext + 1750 " found conn=" + conn); 1751 } 1752 return conn; 1753 } 1754 } 1755 } 1756 if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn"); 1757 return null; 1758 } 1759 1760 @Override 1761 protected void onEnableApn(int apnId, int enabled) { 1762 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId)); 1763 if (apnContext == null) { 1764 loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext"); 1765 return; 1766 } 1767 // TODO change our retry manager to use the appropriate numbers for the new APN 1768 if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState"); 1769 applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet()); 1770 } 1771 1772 @Override 1773 // TODO: We shouldnt need this. 1774 protected boolean onTrySetupData(String reason) { 1775 if (DBG) log("onTrySetupData: reason=" + reason); 1776 setupDataOnReadyApns(reason); 1777 return true; 1778 } 1779 1780 protected boolean onTrySetupData(ApnContext apnContext) { 1781 if (DBG) log("onTrySetupData: apnContext=" + apnContext); 1782 return trySetupData(apnContext); 1783 } 1784 1785 @Override 1786 protected void onRoamingOff() { 1787 if (DBG) log("onRoamingOff"); 1788 1789 if (getDataOnRoamingEnabled() == false) { 1790 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF); 1791 setupDataOnReadyApns(Phone.REASON_ROAMING_OFF); 1792 } else { 1793 notifyDataConnection(Phone.REASON_ROAMING_OFF); 1794 } 1795 } 1796 1797 @Override 1798 protected void onRoamingOn() { 1799 if (getDataOnRoamingEnabled()) { 1800 if (DBG) log("onRoamingOn: setup data on roaming"); 1801 setupDataOnReadyApns(Phone.REASON_ROAMING_ON); 1802 notifyDataConnection(Phone.REASON_ROAMING_ON); 1803 } else { 1804 if (DBG) log("onRoamingOn: Tear down data connection on roaming."); 1805 cleanUpAllConnections(true, Phone.REASON_ROAMING_ON); 1806 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON); 1807 } 1808 } 1809 1810 @Override 1811 protected void onRadioAvailable() { 1812 if (DBG) log("onRadioAvailable"); 1813 if (mPhone.getSimulatedRadioControl() != null) { 1814 // Assume data is connected on the simulator 1815 // FIXME this can be improved 1816 // setState(State.CONNECTED); 1817 notifyDataConnection(null); 1818 1819 log("onRadioAvailable: We're on the simulator; assuming data is connected"); 1820 } 1821 1822 if (mPhone.mIccRecords.getRecordsLoaded()) { 1823 notifyOffApnsOfAvailability(null); 1824 } 1825 1826 if (getOverallState() != State.IDLE) { 1827 cleanUpConnection(true, null); 1828 } 1829 } 1830 1831 @Override 1832 protected void onRadioOffOrNotAvailable() { 1833 // Make sure our reconnect delay starts at the initial value 1834 // next time the radio comes on 1835 1836 for (DataConnection dc : mDataConnections.values()) { 1837 dc.resetRetryCount(); 1838 } 1839 mReregisterOnReconnectFailure = false; 1840 1841 if (mPhone.getSimulatedRadioControl() != null) { 1842 // Assume data is connected on the simulator 1843 // FIXME this can be improved 1844 log("We're on the simulator; assuming radio off is meaningless"); 1845 } else { 1846 if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); 1847 cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF); 1848 } 1849 notifyOffApnsOfAvailability(null); 1850 } 1851 1852 @Override 1853 protected void onDataSetupComplete(AsyncResult ar) { 1854 1855 ApnContext apnContext = null; 1856 1857 if(ar.userObj instanceof ApnContext){ 1858 apnContext = (ApnContext)ar.userObj; 1859 } else { 1860 throw new RuntimeException("onDataSetupComplete: No apnContext"); 1861 } 1862 1863 if (isDataSetupCompleteOk(ar)) { 1864 DataConnectionAc dcac = apnContext.getDataConnectionAc(); 1865 if (dcac == null) { 1866 throw new RuntimeException("onDataSetupCompete: No dcac"); 1867 } 1868 DataConnection dc = apnContext.getDataConnection(); 1869 1870 if (DBG) { 1871 // TODO We may use apnContext.getApnSetting() directly 1872 // instead of getWaitingApns().get(0) 1873 String apnStr = "<unknown>"; 1874 if (apnContext.getWaitingApns() != null 1875 && !apnContext.getWaitingApns().isEmpty()){ 1876 apnStr = apnContext.getWaitingApns().get(0).apn; 1877 } 1878 log("onDataSetupComplete: success apn=" + apnStr); 1879 } 1880 ApnSetting apn = apnContext.getApnSetting(); 1881 if (apn.proxy != null && apn.proxy.length() != 0) { 1882 try { 1883 String port = apn.port; 1884 if (TextUtils.isEmpty(port)) port = "8080"; 1885 ProxyProperties proxy = new ProxyProperties(apn.proxy, 1886 Integer.parseInt(port), null); 1887 dcac.setLinkPropertiesHttpProxySync(proxy); 1888 } catch (NumberFormatException e) { 1889 loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" + 1890 apn.port + "): " + e); 1891 } 1892 } 1893 1894 // everything is setup 1895 if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) { 1896 SystemProperties.set("gsm.defaultpdpcontext.active", "true"); 1897 if (canSetPreferApn && mPreferredApn == null) { 1898 if (DBG) log("onDataSetupComplete: PREFERED APN is null"); 1899 mPreferredApn = apnContext.getApnSetting(); 1900 if (mPreferredApn != null) { 1901 setPreferredApn(mPreferredApn.id); 1902 } 1903 } 1904 } else { 1905 SystemProperties.set("gsm.defaultpdpcontext.active", "false"); 1906 } 1907 notifyDefaultData(apnContext); 1908 } else { 1909 String apnString; 1910 DataConnection.FailCause cause; 1911 1912 cause = (DataConnection.FailCause) (ar.result); 1913 if (DBG) { 1914 try { 1915 apnString = apnContext.getWaitingApns().get(0).apn; 1916 } catch (Exception e) { 1917 apnString = "<unknown>"; 1918 } 1919 log(String.format("onDataSetupComplete: error apn=%s cause=%s", apnString, cause)); 1920 } 1921 if (cause.isEventLoggable()) { 1922 // Log this failure to the Event Logs. 1923 int cid = getCellLocationId(); 1924 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, 1925 cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType()); 1926 } 1927 1928 // Count permanent failures and remove the APN we just tried 1929 if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount(); 1930 1931 apnContext.removeNextWaitingApn(); 1932 if (DBG) { 1933 log(String.format("onDataSetupComplete: WaitingApns.size=%d" + 1934 " WaitingApnsPermFailureCountDown=%d", 1935 apnContext.getWaitingApns().size(), 1936 apnContext.getWaitingApnsPermFailCount())); 1937 } 1938 1939 // See if there are more APN's to try 1940 if (apnContext.getWaitingApns().isEmpty()) { 1941 if (apnContext.getWaitingApnsPermFailCount() == 0) { 1942 if (DBG) { 1943 log("onDataSetupComplete: All APN's had permanent failures, stop retrying"); 1944 } 1945 apnContext.setState(State.FAILED); 1946 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType()); 1947 1948 apnContext.setDataConnection(null); 1949 apnContext.setDataConnectionAc(null); 1950 if (DBG) { 1951 log("onDataSetupComplete: permanent error apn=%s" + apnString ); 1952 } 1953 } else { 1954 if (DBG) log("onDataSetupComplete: Not all permanent failures, retry"); 1955 // check to see if retry should be overridden for this failure. 1956 int retryOverride = -1; 1957 if (ar.exception instanceof DataConnection.CallSetupException) { 1958 retryOverride = 1959 ((DataConnection.CallSetupException)ar.exception).getRetryOverride(); 1960 } 1961 if (retryOverride == RILConstants.MAX_INT) { 1962 if (DBG) log("No retry is suggested."); 1963 } else { 1964 startDelayedRetry(cause, apnContext, retryOverride); 1965 } 1966 } 1967 } else { 1968 if (DBG) log("onDataSetupComplete: Try next APN"); 1969 apnContext.setState(State.SCANNING); 1970 // Wait a bit before trying the next APN, so that 1971 // we're not tying up the RIL command channel 1972 startAlarmForReconnect(APN_DELAY_MILLIS, apnContext); 1973 } 1974 } 1975 } 1976 1977 /** 1978 * Called when EVENT_DISCONNECT_DONE is received. 1979 */ 1980 @Override 1981 protected void onDisconnectDone(int connId, AsyncResult ar) { 1982 ApnContext apnContext = null; 1983 1984 if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE connId=" + connId); 1985 if (ar.userObj instanceof ApnContext) { 1986 apnContext = (ApnContext) ar.userObj; 1987 } else { 1988 loge("Invalid ar in onDisconnectDone"); 1989 return; 1990 } 1991 1992 apnContext.setState(State.IDLE); 1993 1994 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1995 1996 // if all data connection are gone, check whether Airplane mode request was 1997 // pending. 1998 if (isDisconnected()) { 1999 if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { 2000 // Radio will be turned off. No need to retry data setup 2001 apnContext.setApnSetting(null); 2002 apnContext.setDataConnection(null); 2003 apnContext.setDataConnectionAc(null); 2004 return; 2005 } 2006 } 2007 2008 // If APN is still enabled, try to bring it back up automatically 2009 if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) { 2010 SystemProperties.set("gsm.defaultpdpcontext.active", "false"); // TODO - what the heck? This shoudld go 2011 // Wait a bit before trying the next APN, so that 2012 // we're not tying up the RIL command channel. 2013 // This also helps in any external dependency to turn off the context. 2014 startAlarmForReconnect(APN_DELAY_MILLIS, apnContext); 2015 } else { 2016 apnContext.setApnSetting(null); 2017 apnContext.setDataConnection(null); 2018 apnContext.setDataConnectionAc(null); 2019 } 2020 } 2021 2022 protected void onPollPdp() { 2023 if (getOverallState() == State.CONNECTED) { 2024 // only poll when connected 2025 mPhone.mCM.getDataCallList(this.obtainMessage(EVENT_DATA_STATE_CHANGED)); 2026 sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); 2027 } 2028 } 2029 2030 @Override 2031 protected void onVoiceCallStarted() { 2032 if (DBG) log("onVoiceCallStarted"); 2033 if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 2034 if (DBG) log("onVoiceCallStarted stop polling"); 2035 stopNetStatPoll(); 2036 stopDataStallAlarm(); 2037 notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); 2038 } 2039 } 2040 2041 @Override 2042 protected void onVoiceCallEnded() { 2043 if (DBG) log("onVoiceCallEnded"); 2044 if (isConnected()) { 2045 if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 2046 startNetStatPoll(); 2047 startDataStallAlarm(); 2048 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); 2049 } else { 2050 // clean slate after call end. 2051 resetPollStats(); 2052 } 2053 } else { 2054 // reset reconnect timer 2055 setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED); 2056 } 2057 } 2058 2059 @Override 2060 protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) { 2061 if (DBG) log("onCleanUpConnection"); 2062 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId)); 2063 if (apnContext != null) { 2064 apnContext.setReason(reason); 2065 cleanUpConnection(tearDown, apnContext); 2066 } 2067 } 2068 2069 protected boolean isConnected() { 2070 for (ApnContext apnContext : mApnContexts.values()) { 2071 if (apnContext.getState() == State.CONNECTED) { 2072 // At least one context is connected, return true 2073 return true; 2074 } 2075 } 2076 // There are not any contexts connected, return false 2077 return false; 2078 } 2079 2080 @Override 2081 public boolean isDisconnected() { 2082 for (ApnContext apnContext : mApnContexts.values()) { 2083 if (!apnContext.isDisconnected()) { 2084 // At least one context was not disconnected return false 2085 return false; 2086 } 2087 } 2088 // All contexts were disconnected so return true 2089 return true; 2090 } 2091 2092 @Override 2093 protected void notifyDataConnection(String reason) { 2094 if (DBG) log("notifyDataConnection: reason=" + reason); 2095 for (ApnContext apnContext : mApnContexts.values()) { 2096 if (apnContext.isReady()) { 2097 if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType()); 2098 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 2099 apnContext.getApnType()); 2100 } 2101 } 2102 notifyOffApnsOfAvailability(reason); 2103 } 2104 2105 /** 2106 * Based on the sim operator numeric, create a list for all possible 2107 * Data Connections and setup the preferredApn. 2108 */ 2109 private void createAllApnList() { 2110 mAllApns = new ArrayList<ApnSetting>(); 2111 String operator = mPhone.mIccRecords.getOperatorNumeric(); 2112 if (operator != null) { 2113 String selection = "numeric = '" + operator + "'"; 2114 // query only enabled apn. 2115 // carrier_enabled : 1 means enabled apn, 0 disabled apn. 2116 selection += " and carrier_enabled = 1"; 2117 if (DBG) log("createAllApnList: selection=" + selection); 2118 2119 Cursor cursor = mPhone.getContext().getContentResolver().query( 2120 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 2121 2122 if (cursor != null) { 2123 if (cursor.getCount() > 0) { 2124 mAllApns = createApnList(cursor); 2125 } 2126 cursor.close(); 2127 } 2128 } 2129 2130 if (mAllApns.isEmpty()) { 2131 if (DBG) log("createAllApnList: No APN found for carrier: " + operator); 2132 mPreferredApn = null; 2133 // TODO: What is the right behaviour? 2134 //notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN); 2135 } else { 2136 mPreferredApn = getPreferredApn(); 2137 if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { 2138 mPreferredApn = null; 2139 setPreferredApn(-1); 2140 } 2141 if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); 2142 } 2143 if (DBG) log("createAllApnList: X mAllApns=" + mAllApns); 2144 } 2145 2146 /** Return the id for a new data connection */ 2147 private GsmDataConnection createDataConnection() { 2148 if (DBG) log("createDataConnection E"); 2149 2150 RetryManager rm = new RetryManager(); 2151 int id = mUniqueIdGenerator.getAndIncrement(); 2152 GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm); 2153 mDataConnections.put(id, conn); 2154 DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG); 2155 int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler()); 2156 if (status == AsyncChannel.STATUS_SUCCESSFUL) { 2157 mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac); 2158 } else { 2159 loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection + 2160 " status=" + status); 2161 } 2162 2163 // install reconnect intent filter for this data connection. 2164 IntentFilter filter = new IntentFilter(); 2165 filter.addAction(INTENT_RECONNECT_ALARM + '.' + id); 2166 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 2167 2168 if (DBG) log("createDataConnection() X id=" + id); 2169 return conn; 2170 } 2171 2172 private void configureRetry(DataConnection dc, boolean forDefault) { 2173 if (dc == null) return; 2174 2175 if (!dc.configureRetry(getReryConfig(forDefault))) { 2176 if (forDefault) { 2177 if (!dc.configureRetry(DEFAULT_DATA_RETRY_CONFIG)) { 2178 // Should never happen, log an error and default to a simple linear sequence. 2179 loge("configureRetry: Could not configure using " + 2180 "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG); 2181 dc.configureRetry(20, 2000, 1000); 2182 } 2183 } else { 2184 if (!dc.configureRetry(SECONDARY_DATA_RETRY_CONFIG)) { 2185 // Should never happen, log an error and default to a simple sequence. 2186 loge("configureRetry: Could note configure using " + 2187 "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG); 2188 dc.configureRetry("max_retries=3, 333, 333, 333"); 2189 } 2190 } 2191 } 2192 } 2193 2194 private void destroyDataConnections() { 2195 if(mDataConnections != null) { 2196 if (DBG) log("destroyDataConnections: clear mDataConnectionList"); 2197 mDataConnections.clear(); 2198 } else { 2199 if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); 2200 } 2201 } 2202 2203 /** 2204 * Build a list of APNs to be used to create PDP's. 2205 * 2206 * @param requestedApnType 2207 * @return waitingApns list to be used to create PDP 2208 * error when waitingApns.isEmpty() 2209 */ 2210 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) { 2211 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); 2212 2213 if (requestedApnType.equals(Phone.APN_TYPE_DUN)) { 2214 ApnSetting dun = fetchDunApn(); 2215 if (dun != null) { 2216 apnList.add(dun); 2217 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); 2218 return apnList; 2219 } 2220 } 2221 2222 String operator = mPhone.mIccRecords.getOperatorNumeric(); 2223 int radioTech = mPhone.getServiceState().getRadioTechnology(); 2224 2225 if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { 2226 if (canSetPreferApn && mPreferredApn != null) { 2227 if (DBG) { 2228 log("buildWaitingApns: Preferred APN:" + operator + ":" 2229 + mPreferredApn.numeric + ":" + mPreferredApn); 2230 } 2231 if (mPreferredApn.numeric.equals(operator)) { 2232 if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) { 2233 apnList.add(mPreferredApn); 2234 if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); 2235 return apnList; 2236 } else { 2237 if (DBG) log("buildWaitingApns: no preferred APN"); 2238 setPreferredApn(-1); 2239 mPreferredApn = null; 2240 } 2241 } else { 2242 if (DBG) log("buildWaitingApns: no preferred APN"); 2243 setPreferredApn(-1); 2244 mPreferredApn = null; 2245 } 2246 } 2247 } 2248 if (mAllApns != null) { 2249 for (ApnSetting apn : mAllApns) { 2250 if (apn.canHandleType(requestedApnType)) { 2251 if (apn.bearer == 0 || apn.bearer == radioTech) { 2252 if (DBG) log("apn info : " +apn.toString()); 2253 apnList.add(apn); 2254 } 2255 } 2256 } 2257 } else { 2258 loge("mAllApns is empty!"); 2259 } 2260 if (DBG) log("buildWaitingApns: X apnList=" + apnList); 2261 return apnList; 2262 } 2263 2264 private String apnListToString (ArrayList<ApnSetting> apns) { 2265 StringBuilder result = new StringBuilder(); 2266 for (int i = 0, size = apns.size(); i < size; i++) { 2267 result.append('[') 2268 .append(apns.get(i).toString()) 2269 .append(']'); 2270 } 2271 return result.toString(); 2272 } 2273 2274 private void startDelayedRetry(GsmDataConnection.FailCause cause, 2275 ApnContext apnContext, int retryOverride) { 2276 notifyNoData(cause, apnContext); 2277 reconnectAfterFail(cause, apnContext, retryOverride); 2278 } 2279 2280 private void setPreferredApn(int pos) { 2281 if (!canSetPreferApn) { 2282 return; 2283 } 2284 2285 ContentResolver resolver = mPhone.getContext().getContentResolver(); 2286 resolver.delete(PREFERAPN_URI, null, null); 2287 2288 if (pos >= 0) { 2289 ContentValues values = new ContentValues(); 2290 values.put(APN_ID, pos); 2291 resolver.insert(PREFERAPN_URI, values); 2292 } 2293 } 2294 2295 private ApnSetting getPreferredApn() { 2296 if (mAllApns.isEmpty()) { 2297 return null; 2298 } 2299 2300 Cursor cursor = mPhone.getContext().getContentResolver().query( 2301 PREFERAPN_URI, new String[] { "_id", "name", "apn" }, 2302 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 2303 2304 if (cursor != null) { 2305 canSetPreferApn = true; 2306 } else { 2307 canSetPreferApn = false; 2308 } 2309 2310 if (canSetPreferApn && cursor.getCount() > 0) { 2311 int pos; 2312 cursor.moveToFirst(); 2313 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); 2314 for(ApnSetting p:mAllApns) { 2315 if (p.id == pos && p.canHandleType(mRequestedApnType)) { 2316 cursor.close(); 2317 return p; 2318 } 2319 } 2320 } 2321 2322 if (cursor != null) { 2323 cursor.close(); 2324 } 2325 2326 return null; 2327 } 2328 2329 @Override 2330 public void handleMessage (Message msg) { 2331 if (DBG) log("handleMessage msg=" + msg); 2332 2333 if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) { 2334 loge("handleMessage: Ignore GSM msgs since GSM phone is inactive"); 2335 return; 2336 } 2337 2338 switch (msg.what) { 2339 case EVENT_RECORDS_LOADED: 2340 onRecordsLoaded(); 2341 break; 2342 2343 case EVENT_DATA_CONNECTION_DETACHED: 2344 onDataConnectionDetached(); 2345 break; 2346 2347 case EVENT_DATA_CONNECTION_ATTACHED: 2348 onDataConnectionAttached(); 2349 break; 2350 2351 case EVENT_DATA_STATE_CHANGED: 2352 onDataStateChanged((AsyncResult) msg.obj); 2353 break; 2354 2355 case EVENT_POLL_PDP: 2356 onPollPdp(); 2357 break; 2358 2359 case EVENT_DO_RECOVERY: 2360 doRecovery(); 2361 break; 2362 2363 case EVENT_APN_CHANGED: 2364 onApnChanged(); 2365 break; 2366 2367 case EVENT_PS_RESTRICT_ENABLED: 2368 /** 2369 * We don't need to explicitly to tear down the PDP context 2370 * when PS restricted is enabled. The base band will deactive 2371 * PDP context and notify us with PDP_CONTEXT_CHANGED. 2372 * But we should stop the network polling and prevent reset PDP. 2373 */ 2374 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); 2375 stopNetStatPoll(); 2376 stopDataStallAlarm(); 2377 mIsPsRestricted = true; 2378 break; 2379 2380 case EVENT_PS_RESTRICT_DISABLED: 2381 /** 2382 * When PS restrict is removed, we need setup PDP connection if 2383 * PDP connection is down. 2384 */ 2385 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); 2386 mIsPsRestricted = false; 2387 if (isConnected()) { 2388 startNetStatPoll(); 2389 startDataStallAlarm(); 2390 } else { 2391 // TODO: Should all PDN states be checked to fail? 2392 if (mState == State.FAILED) { 2393 cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED); 2394 resetAllRetryCounts(); 2395 mReregisterOnReconnectFailure = false; 2396 } 2397 trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, Phone.APN_TYPE_DEFAULT); 2398 } 2399 break; 2400 case EVENT_TRY_SETUP_DATA: 2401 if (msg.obj instanceof ApnContext) { 2402 onTrySetupData((ApnContext)msg.obj); 2403 } else if (msg.obj instanceof String) { 2404 onTrySetupData((String)msg.obj); 2405 } else { 2406 loge("EVENT_TRY_SETUP request w/o apnContext or String"); 2407 } 2408 break; 2409 2410 case EVENT_CLEAN_UP_CONNECTION: 2411 boolean tearDown = (msg.arg1 == 0) ? false : true; 2412 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown); 2413 if (msg.obj instanceof ApnContext) { 2414 cleanUpConnection(tearDown, (ApnContext)msg.obj); 2415 } else { 2416 loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context"); 2417 } 2418 break; 2419 default: 2420 // handle the message in the super class DataConnectionTracker 2421 super.handleMessage(msg); 2422 break; 2423 } 2424 } 2425 2426 protected int getApnProfileID(String apnType) { 2427 if (TextUtils.equals(apnType, Phone.APN_TYPE_IMS)) { 2428 return RILConstants.DATA_PROFILE_IMS; 2429 } else if (TextUtils.equals(apnType, Phone.APN_TYPE_FOTA)) { 2430 return RILConstants.DATA_PROFILE_FOTA; 2431 } else if (TextUtils.equals(apnType, Phone.APN_TYPE_CBS)) { 2432 return RILConstants.DATA_PROFILE_CBS; 2433 } else { 2434 return RILConstants.DATA_PROFILE_DEFAULT; 2435 } 2436 } 2437 2438 private int getCellLocationId() { 2439 int cid = -1; 2440 CellLocation loc = mPhone.getCellLocation(); 2441 2442 if (loc != null) { 2443 if (loc instanceof GsmCellLocation) { 2444 cid = ((GsmCellLocation)loc).getCid(); 2445 } else if (loc instanceof CdmaCellLocation) { 2446 cid = ((CdmaCellLocation)loc).getBaseStationId(); 2447 } 2448 } 2449 return cid; 2450 } 2451 2452 @Override 2453 protected void log(String s) { 2454 Log.d(LOG_TAG, "[GsmDCT] "+ s); 2455 } 2456 2457 @Override 2458 protected void loge(String s) { 2459 Log.e(LOG_TAG, "[GsmDCT] " + s); 2460 } 2461 } 2462