1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.dataconnection; 18 19 import android.app.AlarmManager; 20 import android.app.PendingIntent; 21 import android.content.BroadcastReceiver; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.SharedPreferences; 27 import android.database.ContentObserver; 28 import android.net.ConnectivityManager; 29 import android.net.LinkCapabilities; 30 import android.net.LinkProperties; 31 import android.net.NetworkInfo; 32 import android.net.TrafficStats; 33 import android.net.wifi.WifiManager; 34 import android.os.AsyncResult; 35 import android.os.Build; 36 import android.os.Bundle; 37 import android.os.Handler; 38 import android.os.HandlerThread; 39 import android.os.Message; 40 import android.os.Messenger; 41 import android.os.SystemClock; 42 import android.os.SystemProperties; 43 import android.preference.PreferenceManager; 44 import android.provider.Settings; 45 import android.provider.Settings.SettingNotFoundException; 46 import android.telephony.TelephonyManager; 47 import android.text.TextUtils; 48 import android.util.EventLog; 49 import android.telephony.Rlog; 50 51 import com.android.internal.R; 52 import com.android.internal.telephony.DctConstants; 53 import com.android.internal.telephony.DctConstants.State; 54 import com.android.internal.telephony.EventLogTags; 55 import com.android.internal.telephony.Phone; 56 import com.android.internal.telephony.PhoneBase; 57 import com.android.internal.telephony.PhoneConstants; 58 import com.android.internal.telephony.uicc.IccRecords; 59 import com.android.internal.telephony.uicc.UiccController; 60 import com.android.internal.util.AsyncChannel; 61 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.HashMap; 66 import java.util.Map.Entry; 67 import java.util.Set; 68 import java.util.concurrent.ConcurrentHashMap; 69 import java.util.concurrent.atomic.AtomicInteger; 70 import java.util.concurrent.atomic.AtomicReference; 71 72 /** 73 * {@hide} 74 */ 75 public abstract class DcTrackerBase extends Handler { 76 protected static final boolean DBG = true; 77 protected static final boolean VDBG = false; // STOPSHIP if true 78 protected static final boolean VDBG_STALL = true; // STOPSHIP if true 79 protected static final boolean RADIO_TESTS = false; 80 81 /** 82 * Constants for the data connection activity: 83 * physical link down/up 84 */ 85 protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0; 86 protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1; 87 protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2; 88 89 /** Delay between APN attempts. 90 Note the property override mechanism is there just for testing purpose only. */ 91 protected static final int APN_DELAY_DEFAULT_MILLIS = 20000; 92 93 /** Delay between APN attempts when in fail fast mode */ 94 protected static final int APN_FAIL_FAST_DELAY_DEFAULT_MILLIS = 3000; 95 96 AlarmManager mAlarmManager; 97 98 protected Object mDataEnabledLock = new Object(); 99 100 // responds to the setInternalDataEnabled call - used internally to turn off data 101 // for example during emergency calls 102 protected boolean mInternalDataEnabled = true; 103 104 // responds to public (user) API to enable/disable data use 105 // independent of mInternalDataEnabled and requests for APN access 106 // persisted 107 protected boolean mUserDataEnabled = true; 108 109 // TODO: move away from static state once 5587429 is fixed. 110 protected static boolean sPolicyDataEnabled = true; 111 112 private boolean[] mDataEnabled = new boolean[DctConstants.APN_NUM_TYPES]; 113 114 private int mEnabledCount = 0; 115 116 /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ 117 protected String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 118 119 /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ 120 protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," 121 + "5000,10000,20000,40000,80000:5000,160000:5000," 122 + "320000:5000,640000:5000,1280000:5000,1800000:5000"; 123 124 /** Retry configuration for secondary networks: 4 tries in 20 sec */ 125 protected static final String SECONDARY_DATA_RETRY_CONFIG = 126 "max_retries=3, 5000, 5000, 5000"; 127 128 /** Slow poll when attempting connection recovery. */ 129 protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; 130 /** Default max failure count before attempting to network re-registration. */ 131 protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3; 132 133 /** 134 * After detecting a potential connection problem, this is the max number 135 * of subsequent polls before attempting recovery. 136 */ 137 protected static final int NO_RECV_POLL_LIMIT = 24; 138 // 1 sec. default polling interval when screen is on. 139 protected static final int POLL_NETSTAT_MILLIS = 1000; 140 // 10 min. default polling interval when screen is off. 141 protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; 142 // 2 min for round trip time 143 protected static final int POLL_LONGEST_RTT = 120 * 1000; 144 // Default sent packets without ack which triggers initial recovery steps 145 protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; 146 // how long to wait before switching back to default APN 147 protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; 148 // system property that can override the above value 149 protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; 150 // represents an invalid IP address 151 protected static final String NULL_IP = "0.0.0.0"; 152 153 // Default for the data stall alarm while non-aggressive stall detection 154 protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; 155 // Default for the data stall alarm for aggressive stall detection 156 protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; 157 // If attempt is less than this value we're doing first level recovery 158 protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1; 159 // Tag for tracking stale alarms 160 protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag"; 161 162 protected static final boolean DATA_STALL_SUSPECTED = true; 163 protected static final boolean DATA_STALL_NOT_SUSPECTED = false; 164 165 protected String RADIO_RESET_PROPERTY = "gsm.radioreset"; 166 167 protected static final String INTENT_RECONNECT_ALARM = 168 "com.android.internal.telephony.data-reconnect"; 169 protected static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type"; 170 protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = 171 "reconnect_alarm_extra_reason"; 172 173 protected static final String INTENT_RESTART_TRYSETUP_ALARM = 174 "com.android.internal.telephony.data-restart-trysetup"; 175 protected static final String INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE = 176 "restart_trysetup_alarm_extra_type"; 177 178 protected static final String INTENT_DATA_STALL_ALARM = 179 "com.android.internal.telephony.data-stall"; 180 181 182 183 protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot"; 184 185 protected DcTesterFailBringUpAll mDcTesterFailBringUpAll; 186 protected DcController mDcc; 187 188 // member variables 189 protected PhoneBase mPhone; 190 protected UiccController mUiccController; 191 protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>(); 192 protected DctConstants.Activity mActivity = DctConstants.Activity.NONE; 193 protected DctConstants.State mState = DctConstants.State.IDLE; 194 protected Handler mDataConnectionTracker = null; 195 196 protected long mTxPkts; 197 protected long mRxPkts; 198 protected int mNetStatPollPeriod; 199 protected boolean mNetStatPollEnabled = false; 200 201 protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); 202 // Used to track stale data stall alarms. 203 protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); 204 // The current data stall alarm intent 205 protected PendingIntent mDataStallAlarmIntent = null; 206 // Number of packets sent since the last received packet 207 protected long mSentSinceLastRecv; 208 // Controls when a simple recovery attempt it to be tried 209 protected int mNoRecvPollCount = 0; 210 // Refrence counter for enabling fail fast 211 protected static int sEnableFailFastRefCounter = 0; 212 // True if data stall detection is enabled 213 protected volatile boolean mDataStallDetectionEnabled = true; 214 215 protected volatile boolean mFailFast = false; 216 217 // True when in voice call 218 protected boolean mInVoiceCall = false; 219 220 // wifi connection status will be updated by sticky intent 221 protected boolean mIsWifiConnected = false; 222 223 /** Intent sent when the reconnect alarm fires. */ 224 protected PendingIntent mReconnectIntent = null; 225 226 /** CID of active data connection */ 227 protected int mCidActive; 228 229 // When false we will not auto attach and manually attaching is required. 230 protected boolean mAutoAttachOnCreation = false; 231 232 // State of screen 233 // (TODO: Reconsider tying directly to screen, maybe this is 234 // really a lower power mode") 235 protected boolean mIsScreenOn = true; 236 237 /** Allows the generation of unique Id's for DataConnection objects */ 238 protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); 239 240 /** The data connections. */ 241 protected HashMap<Integer, DataConnection> mDataConnections = 242 new HashMap<Integer, DataConnection>(); 243 244 /** The data connection async channels */ 245 protected HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap = 246 new HashMap<Integer, DcAsyncChannel>(); 247 248 /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ 249 protected HashMap<String, Integer> mApnToDataConnectionId = 250 new HashMap<String, Integer>(); 251 252 /** Phone.APN_TYPE_* ===> ApnContext */ 253 protected ConcurrentHashMap<String, ApnContext> mApnContexts = 254 new ConcurrentHashMap<String, ApnContext>(); 255 256 /* Currently active APN */ 257 protected ApnSetting mActiveApn; 258 259 /** allApns holds all apns */ 260 protected ArrayList<ApnSetting> mAllApnSettings = null; 261 262 /** preferred apn */ 263 protected ApnSetting mPreferredApn = null; 264 265 /** Is packet service restricted by network */ 266 protected boolean mIsPsRestricted = false; 267 268 /* Once disposed dont handle any messages */ 269 protected boolean mIsDisposed = false; 270 271 protected ContentResolver mResolver; 272 273 /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */ 274 protected boolean mIsProvisioning = false; 275 276 /* Object parameter in CMD_ENABLE_MOBILE_PROVISIONING */ 277 protected String mProvisioningUrl = null; 278 279 protected AsyncChannel mReplyAc = new AsyncChannel(); 280 281 protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver () 282 { 283 @Override 284 public void onReceive(Context context, Intent intent) 285 { 286 String action = intent.getAction(); 287 if (DBG) log("onReceive: action=" + action); 288 if (action.equals(Intent.ACTION_SCREEN_ON)) { 289 mIsScreenOn = true; 290 stopNetStatPoll(); 291 startNetStatPoll(); 292 restartDataStallAlarm(); 293 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 294 mIsScreenOn = false; 295 stopNetStatPoll(); 296 startNetStatPoll(); 297 restartDataStallAlarm(); 298 } else if (action.startsWith(INTENT_RECONNECT_ALARM)) { 299 if (DBG) log("Reconnect alarm. Previous state was " + mState); 300 onActionIntentReconnectAlarm(intent); 301 } else if (action.startsWith(INTENT_RESTART_TRYSETUP_ALARM)) { 302 if (DBG) log("Restart trySetup alarm"); 303 onActionIntentRestartTrySetupAlarm(intent); 304 } else if (action.equals(INTENT_DATA_STALL_ALARM)) { 305 onActionIntentDataStallAlarm(intent); 306 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 307 final android.net.NetworkInfo networkInfo = (NetworkInfo) 308 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 309 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); 310 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected); 311 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 312 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 313 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 314 315 if (!enabled) { 316 // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION 317 // quit and won't report disconnected until next enabling. 318 mIsWifiConnected = false; 319 } 320 if (DBG) log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled 321 + " mIsWifiConnected=" + mIsWifiConnected); 322 } 323 } 324 }; 325 326 private Runnable mPollNetStat = new Runnable() 327 { 328 @Override 329 public void run() { 330 updateDataActivity(); 331 332 if (mIsScreenOn) { 333 mNetStatPollPeriod = Settings.Global.getInt(mResolver, 334 Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); 335 } else { 336 mNetStatPollPeriod = Settings.Global.getInt(mResolver, 337 Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, 338 POLL_NETSTAT_SCREEN_OFF_MILLIS); 339 } 340 341 if (mNetStatPollEnabled) { 342 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); 343 } 344 } 345 }; 346 347 private class DataRoamingSettingObserver extends ContentObserver { 348 349 public DataRoamingSettingObserver(Handler handler, Context context) { 350 super(handler); 351 mResolver = context.getContentResolver(); 352 } 353 354 public void register() { 355 mResolver.registerContentObserver( 356 Settings.Global.getUriFor(Settings.Global.DATA_ROAMING), false, this); 357 } 358 359 public void unregister() { 360 mResolver.unregisterContentObserver(this); 361 } 362 363 @Override 364 public void onChange(boolean selfChange) { 365 // already running on mPhone handler thread 366 if (mPhone.getServiceState().getRoaming()) { 367 sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON)); 368 } 369 } 370 } 371 private final DataRoamingSettingObserver mDataRoamingSettingObserver; 372 373 /** 374 * The Initial MaxRetry sent to a DataConnection as a parameter 375 * to DataConnectionAc.bringUp. This value can be defined at compile 376 * time using the SystemProperty Settings.Global.DCT_INITIAL_MAX_RETRY 377 * and at runtime using gservices to change Settings.Global.DCT_INITIAL_MAX_RETRY. 378 */ 379 private static final int DEFAULT_MDC_INITIAL_RETRY = 1; 380 protected int getInitialMaxRetry() { 381 if (mFailFast) { 382 return 0; 383 } 384 // Get default value from system property or use DEFAULT_MDC_INITIAL_RETRY 385 int value = SystemProperties.getInt( 386 Settings.Global.MDC_INITIAL_MAX_RETRY, DEFAULT_MDC_INITIAL_RETRY); 387 388 // Check if its been overridden 389 return Settings.Global.getInt(mResolver, 390 Settings.Global.MDC_INITIAL_MAX_RETRY, value); 391 } 392 393 /** 394 * Maintain the sum of transmit and receive packets. 395 * 396 * The packet counts are initialized and reset to -1 and 397 * remain -1 until they can be updated. 398 */ 399 public class TxRxSum { 400 public long txPkts; 401 public long rxPkts; 402 403 public TxRxSum() { 404 reset(); 405 } 406 407 public TxRxSum(long txPkts, long rxPkts) { 408 this.txPkts = txPkts; 409 this.rxPkts = rxPkts; 410 } 411 412 public TxRxSum(TxRxSum sum) { 413 txPkts = sum.txPkts; 414 rxPkts = sum.rxPkts; 415 } 416 417 public void reset() { 418 txPkts = -1; 419 rxPkts = -1; 420 } 421 422 @Override 423 public String toString() { 424 return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; 425 } 426 427 public void updateTxRxSum() { 428 this.txPkts = TrafficStats.getMobileTcpTxPackets(); 429 this.rxPkts = TrafficStats.getMobileTcpRxPackets(); 430 } 431 } 432 433 protected void onActionIntentReconnectAlarm(Intent intent) { 434 String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); 435 String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE); 436 437 ApnContext apnContext = mApnContexts.get(apnType); 438 439 if (DBG) { 440 log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason + 441 " apnType=" + apnType + " apnContext=" + apnContext + 442 " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap); 443 } 444 445 if ((apnContext != null) && (apnContext.isEnabled())) { 446 apnContext.setReason(reason); 447 DctConstants.State apnContextState = apnContext.getState(); 448 if (DBG) { 449 log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState); 450 } 451 if ((apnContextState == DctConstants.State.FAILED) 452 || (apnContextState == DctConstants.State.IDLE)) { 453 if (DBG) { 454 log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate"); 455 } 456 DcAsyncChannel dcac = apnContext.getDcAc(); 457 if (dcac != null) { 458 dcac.tearDown(apnContext, "", null); 459 } 460 apnContext.setDataConnectionAc(null); 461 apnContext.setState(DctConstants.State.IDLE); 462 } else { 463 if (DBG) log("onActionIntentReconnectAlarm: keep associated"); 464 } 465 // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA??? 466 sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext)); 467 468 apnContext.setReconnectIntent(null); 469 } 470 } 471 472 protected void onActionIntentRestartTrySetupAlarm(Intent intent) { 473 String apnType = intent.getStringExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE); 474 ApnContext apnContext = mApnContexts.get(apnType); 475 if (DBG) { 476 log("onActionIntentRestartTrySetupAlarm: mState=" + mState + 477 " apnType=" + apnType + " apnContext=" + apnContext + 478 " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap); 479 } 480 sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext)); 481 } 482 483 protected void onActionIntentDataStallAlarm(Intent intent) { 484 if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); 485 Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM, 486 intent.getAction()); 487 msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0); 488 sendMessage(msg); 489 } 490 491 ConnectivityManager mCm; 492 493 /** 494 * Default constructor 495 */ 496 protected DcTrackerBase(PhoneBase phone) { 497 super(); 498 if (DBG) log("DCT.constructor"); 499 mPhone = phone; 500 mResolver = mPhone.getContext().getContentResolver(); 501 mUiccController = UiccController.getInstance(); 502 mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null); 503 mAlarmManager = 504 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 505 mCm = (ConnectivityManager) mPhone.getContext().getSystemService( 506 Context.CONNECTIVITY_SERVICE); 507 508 509 IntentFilter filter = new IntentFilter(); 510 filter.addAction(Intent.ACTION_SCREEN_ON); 511 filter.addAction(Intent.ACTION_SCREEN_OFF); 512 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 513 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 514 filter.addAction(INTENT_DATA_STALL_ALARM); 515 516 mUserDataEnabled = Settings.Global.getInt( 517 mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, 1) == 1; 518 519 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 520 521 // This preference tells us 1) initial condition for "dataEnabled", 522 // and 2) whether the RIL will setup the baseband to auto-PS attach. 523 524 mDataEnabled[DctConstants.APN_DEFAULT_ID] = 525 SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,true); 526 if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) { 527 mEnabledCount++; 528 } 529 530 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); 531 mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false); 532 533 // Watch for changes to Settings.Global.DATA_ROAMING 534 mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone, mPhone.getContext()); 535 mDataRoamingSettingObserver.register(); 536 537 HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread"); 538 dcHandlerThread.start(); 539 Handler dcHandler = new Handler(dcHandlerThread.getLooper()); 540 mDcc = DcController.makeDcc(mPhone, this, dcHandler); 541 mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler); 542 } 543 544 public void dispose() { 545 if (DBG) log("DCT.dispose"); 546 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 547 dcac.disconnect(); 548 } 549 mDataConnectionAcHashMap.clear(); 550 mIsDisposed = true; 551 mPhone.getContext().unregisterReceiver(mIntentReceiver); 552 mUiccController.unregisterForIccChanged(this); 553 mDataRoamingSettingObserver.unregister(); 554 mDcc.dispose(); 555 mDcTesterFailBringUpAll.dispose(); 556 } 557 558 public DctConstants.Activity getActivity() { 559 return mActivity; 560 } 561 562 public boolean isApnTypeActive(String type) { 563 // TODO: support simultaneous with List instead 564 if (PhoneConstants.APN_TYPE_DUN.equals(type)) { 565 ApnSetting dunApn = fetchDunApn(); 566 if (dunApn != null) { 567 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString()))); 568 } 569 } 570 return mActiveApn != null && mActiveApn.canHandleType(type); 571 } 572 573 protected ApnSetting fetchDunApn() { 574 if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) { 575 log("fetchDunApn: net.tethering.noprovisioning=true ret: null"); 576 return null; 577 } 578 Context c = mPhone.getContext(); 579 String apnData = Settings.Global.getString(c.getContentResolver(), 580 Settings.Global.TETHER_DUN_APN); 581 ApnSetting dunSetting = ApnSetting.fromString(apnData); 582 if (dunSetting != null) { 583 if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting); 584 return dunSetting; 585 } 586 587 apnData = c.getResources().getString(R.string.config_tether_apndata); 588 dunSetting = ApnSetting.fromString(apnData); 589 if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + dunSetting); 590 return dunSetting; 591 } 592 593 public String[] getActiveApnTypes() { 594 String[] result; 595 if (mActiveApn != null) { 596 result = mActiveApn.types; 597 } else { 598 result = new String[1]; 599 result[0] = PhoneConstants.APN_TYPE_DEFAULT; 600 } 601 return result; 602 } 603 604 /** TODO: See if we can remove */ 605 public String getActiveApnString(String apnType) { 606 String result = null; 607 if (mActiveApn != null) { 608 result = mActiveApn.apn; 609 } 610 return result; 611 } 612 613 /** 614 * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value. 615 */ 616 public void setDataOnRoamingEnabled(boolean enabled) { 617 if (getDataOnRoamingEnabled() != enabled) { 618 final ContentResolver resolver = mPhone.getContext().getContentResolver(); 619 Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, enabled ? 1 : 0); 620 // will trigger handleDataOnRoamingChange() through observer 621 } 622 } 623 624 /** 625 * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. 626 */ 627 public boolean getDataOnRoamingEnabled() { 628 try { 629 final ContentResolver resolver = mPhone.getContext().getContentResolver(); 630 return Settings.Global.getInt(resolver, Settings.Global.DATA_ROAMING) != 0; 631 } catch (SettingNotFoundException snfe) { 632 return false; 633 } 634 } 635 636 // abstract methods 637 protected abstract void restartRadio(); 638 protected abstract void log(String s); 639 protected abstract void loge(String s); 640 protected abstract boolean isDataAllowed(); 641 protected abstract boolean isApnTypeAvailable(String type); 642 public abstract DctConstants.State getState(String apnType); 643 protected abstract boolean isProvisioningApn(String apnType); 644 protected abstract void setState(DctConstants.State s); 645 protected abstract void gotoIdleAndNotifyDataConnection(String reason); 646 647 protected abstract boolean onTrySetupData(String reason); 648 protected abstract void onRoamingOff(); 649 protected abstract void onRoamingOn(); 650 protected abstract void onRadioAvailable(); 651 protected abstract void onRadioOffOrNotAvailable(); 652 protected abstract void onDataSetupComplete(AsyncResult ar); 653 protected abstract void onDataSetupCompleteError(AsyncResult ar); 654 protected abstract void onDisconnectDone(int connId, AsyncResult ar); 655 protected abstract void onDisconnectDcRetrying(int connId, AsyncResult ar); 656 protected abstract void onVoiceCallStarted(); 657 protected abstract void onVoiceCallEnded(); 658 protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason); 659 protected abstract void onCleanUpAllConnections(String cause); 660 public abstract boolean isDataPossible(String apnType); 661 protected abstract void onUpdateIcc(); 662 protected abstract void completeConnection(ApnContext apnContext); 663 664 @Override 665 public void handleMessage(Message msg) { 666 switch (msg.what) { 667 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 668 log("DISCONNECTED_CONNECTED: msg=" + msg); 669 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj; 670 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync()); 671 dcac.disconnected(); 672 break; 673 } 674 case DctConstants.EVENT_ENABLE_NEW_APN: 675 onEnableApn(msg.arg1, msg.arg2); 676 break; 677 678 case DctConstants.EVENT_TRY_SETUP_DATA: 679 String reason = null; 680 if (msg.obj instanceof String) { 681 reason = (String) msg.obj; 682 } 683 onTrySetupData(reason); 684 break; 685 686 case DctConstants.EVENT_DATA_STALL_ALARM: 687 onDataStallAlarm(msg.arg1); 688 break; 689 690 case DctConstants.EVENT_ROAMING_OFF: 691 onRoamingOff(); 692 break; 693 694 case DctConstants.EVENT_ROAMING_ON: 695 onRoamingOn(); 696 break; 697 698 case DctConstants.EVENT_RADIO_AVAILABLE: 699 onRadioAvailable(); 700 break; 701 702 case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 703 onRadioOffOrNotAvailable(); 704 break; 705 706 case DctConstants.EVENT_DATA_SETUP_COMPLETE: 707 mCidActive = msg.arg1; 708 onDataSetupComplete((AsyncResult) msg.obj); 709 break; 710 711 case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR: 712 onDataSetupCompleteError((AsyncResult) msg.obj); 713 break; 714 715 case DctConstants.EVENT_DISCONNECT_DONE: 716 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg); 717 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj); 718 break; 719 720 case DctConstants.EVENT_DISCONNECT_DC_RETRYING: 721 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg); 722 onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj); 723 break; 724 725 case DctConstants.EVENT_VOICE_CALL_STARTED: 726 onVoiceCallStarted(); 727 break; 728 729 case DctConstants.EVENT_VOICE_CALL_ENDED: 730 onVoiceCallEnded(); 731 break; 732 733 case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: { 734 onCleanUpAllConnections((String) msg.obj); 735 break; 736 } 737 case DctConstants.EVENT_CLEAN_UP_CONNECTION: { 738 boolean tearDown = (msg.arg1 == 0) ? false : true; 739 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj); 740 break; 741 } 742 case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: { 743 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 744 onSetInternalDataEnabled(enabled); 745 break; 746 } 747 case DctConstants.EVENT_RESET_DONE: { 748 if (DBG) log("EVENT_RESET_DONE"); 749 onResetDone((AsyncResult) msg.obj); 750 break; 751 } 752 case DctConstants.CMD_SET_USER_DATA_ENABLE: { 753 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 754 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled); 755 onSetUserDataEnabled(enabled); 756 break; 757 } 758 case DctConstants.CMD_SET_DEPENDENCY_MET: { 759 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false; 760 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met); 761 Bundle bundle = msg.getData(); 762 if (bundle != null) { 763 String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); 764 if (apnType != null) { 765 onSetDependencyMet(apnType, met); 766 } 767 } 768 break; 769 } 770 case DctConstants.CMD_SET_POLICY_DATA_ENABLE: { 771 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 772 onSetPolicyDataEnabled(enabled); 773 break; 774 } 775 case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: { 776 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1; 777 if (DBG) { 778 log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " 779 + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); 780 } 781 if (sEnableFailFastRefCounter < 0) { 782 final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " 783 + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0"; 784 loge(s); 785 sEnableFailFastRefCounter = 0; 786 } 787 final boolean enabled = sEnableFailFastRefCounter > 0; 788 if (DBG) { 789 log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled 790 + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); 791 } 792 if (mFailFast != enabled) { 793 mFailFast = enabled; 794 mDataStallDetectionEnabled = !enabled; 795 if (mDataStallDetectionEnabled 796 && (getOverallState() == DctConstants.State.CONNECTED) 797 && (!mInVoiceCall || 798 mPhone.getServiceStateTracker() 799 .isConcurrentVoiceAndDataAllowed())) { 800 if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall"); 801 stopDataStallAlarm(); 802 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 803 } else { 804 if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall"); 805 stopDataStallAlarm(); 806 } 807 } 808 809 break; 810 } 811 case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: { 812 // TODO: Right now we know when it ends "successfully" when 813 // provisioning apn gets dropped, what happens if the user never 814 // succeed, I assume there is a timeout and the network will drop 815 // it after a period of time. 816 Bundle bundle = msg.getData(); 817 if (bundle != null) { 818 try { 819 mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY); 820 } catch(ClassCastException e) { 821 loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e); 822 mProvisioningUrl = null; 823 } 824 } 825 if (TextUtils.isEmpty(mProvisioningUrl)) { 826 loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring"); 827 mIsProvisioning = false; 828 mProvisioningUrl = null; 829 } else { 830 ApnContext apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT); 831 if (apnContext.isProvisioningApn() && apnContext.getState() == State.CONNECTED){ 832 log("CMD_ENABLE_MOBILE_PROVISIONING: mIsProvisioning=true url=" 833 + mProvisioningUrl); 834 mIsProvisioning = true; 835 completeConnection(mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT)); 836 } else { 837 log("CMD_ENABLE_MOBILE_PROVISIONING: No longer connected"); 838 mIsProvisioning = false; 839 mProvisioningUrl = null; 840 } 841 } 842 break; 843 } 844 case DctConstants.CMD_IS_PROVISIONING_APN: { 845 if (DBG) log("CMD_IS_PROVISIONING_APN"); 846 boolean isProvApn; 847 try { 848 String apnType = null; 849 Bundle bundle = msg.getData(); 850 if (bundle != null) { 851 apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); 852 } 853 if (TextUtils.isEmpty(apnType)) { 854 loge("CMD_IS_PROVISIONING_APN: apnType is empty"); 855 isProvApn = false; 856 } else { 857 isProvApn = isProvisioningApn(apnType); 858 } 859 } catch (ClassCastException e) { 860 loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring"); 861 isProvApn = false; 862 } 863 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn); 864 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN, 865 isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED); 866 break; 867 } 868 case DctConstants.EVENT_ICC_CHANGED: { 869 onUpdateIcc(); 870 break; 871 } 872 case DctConstants.EVENT_RESTART_RADIO: { 873 restartRadio(); 874 break; 875 } 876 default: 877 Rlog.e("DATA", "Unidentified event msg=" + msg); 878 break; 879 } 880 } 881 882 /** 883 * Report on whether data connectivity is enabled 884 * 885 * @return {@code false} if data connectivity has been explicitly disabled, 886 * {@code true} otherwise. 887 */ 888 public boolean getAnyDataEnabled() { 889 final boolean result; 890 synchronized (mDataEnabledLock) { 891 result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled 892 && (mEnabledCount != 0)); 893 } 894 if (!result && DBG) log("getAnyDataEnabled " + result); 895 return result; 896 } 897 898 protected boolean isEmergency() { 899 final boolean result; 900 synchronized (mDataEnabledLock) { 901 result = mPhone.isInEcm() || mPhone.isInEmergencyCall(); 902 } 903 log("isEmergency: result=" + result); 904 return result; 905 } 906 907 protected int apnTypeToId(String type) { 908 if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DEFAULT)) { 909 return DctConstants.APN_DEFAULT_ID; 910 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_MMS)) { 911 return DctConstants.APN_MMS_ID; 912 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_SUPL)) { 913 return DctConstants.APN_SUPL_ID; 914 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DUN)) { 915 return DctConstants.APN_DUN_ID; 916 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_HIPRI)) { 917 return DctConstants.APN_HIPRI_ID; 918 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IMS)) { 919 return DctConstants.APN_IMS_ID; 920 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_FOTA)) { 921 return DctConstants.APN_FOTA_ID; 922 } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_CBS)) { 923 return DctConstants.APN_CBS_ID; 924 } else { 925 return DctConstants.APN_INVALID_ID; 926 } 927 } 928 929 protected String apnIdToType(int id) { 930 switch (id) { 931 case DctConstants.APN_DEFAULT_ID: 932 return PhoneConstants.APN_TYPE_DEFAULT; 933 case DctConstants.APN_MMS_ID: 934 return PhoneConstants.APN_TYPE_MMS; 935 case DctConstants.APN_SUPL_ID: 936 return PhoneConstants.APN_TYPE_SUPL; 937 case DctConstants.APN_DUN_ID: 938 return PhoneConstants.APN_TYPE_DUN; 939 case DctConstants.APN_HIPRI_ID: 940 return PhoneConstants.APN_TYPE_HIPRI; 941 case DctConstants.APN_IMS_ID: 942 return PhoneConstants.APN_TYPE_IMS; 943 case DctConstants.APN_FOTA_ID: 944 return PhoneConstants.APN_TYPE_FOTA; 945 case DctConstants.APN_CBS_ID: 946 return PhoneConstants.APN_TYPE_CBS; 947 default: 948 log("Unknown id (" + id + ") in apnIdToType"); 949 return PhoneConstants.APN_TYPE_DEFAULT; 950 } 951 } 952 953 public LinkProperties getLinkProperties(String apnType) { 954 int id = apnTypeToId(apnType); 955 956 if (isApnIdEnabled(id)) { 957 DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0); 958 return dcac.getLinkPropertiesSync(); 959 } else { 960 return new LinkProperties(); 961 } 962 } 963 964 public LinkCapabilities getLinkCapabilities(String apnType) { 965 int id = apnTypeToId(apnType); 966 if (isApnIdEnabled(id)) { 967 DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0); 968 return dcac.getLinkCapabilitiesSync(); 969 } else { 970 return new LinkCapabilities(); 971 } 972 } 973 974 // tell all active apns of the current condition 975 protected void notifyDataConnection(String reason) { 976 for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) { 977 if (mDataEnabled[id]) { 978 mPhone.notifyDataConnection(reason, apnIdToType(id)); 979 } 980 } 981 notifyOffApnsOfAvailability(reason); 982 } 983 984 // a new APN has gone active and needs to send events to catch up with the 985 // current condition 986 private void notifyApnIdUpToCurrent(String reason, int apnId) { 987 switch (mState) { 988 case IDLE: 989 break; 990 case RETRYING: 991 case CONNECTING: 992 case SCANNING: 993 mPhone.notifyDataConnection(reason, apnIdToType(apnId), 994 PhoneConstants.DataState.CONNECTING); 995 break; 996 case CONNECTED: 997 case DISCONNECTING: 998 mPhone.notifyDataConnection(reason, apnIdToType(apnId), 999 PhoneConstants.DataState.CONNECTING); 1000 mPhone.notifyDataConnection(reason, apnIdToType(apnId), 1001 PhoneConstants.DataState.CONNECTED); 1002 break; 1003 default: 1004 // Ignore 1005 break; 1006 } 1007 } 1008 1009 // since we normally don't send info to a disconnected APN, we need to do this specially 1010 private void notifyApnIdDisconnected(String reason, int apnId) { 1011 mPhone.notifyDataConnection(reason, apnIdToType(apnId), 1012 PhoneConstants.DataState.DISCONNECTED); 1013 } 1014 1015 // disabled apn's still need avail/unavail notificiations - send them out 1016 protected void notifyOffApnsOfAvailability(String reason) { 1017 if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason); 1018 for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) { 1019 if (!isApnIdEnabled(id)) { 1020 notifyApnIdDisconnected(reason, id); 1021 } 1022 } 1023 } 1024 1025 public boolean isApnTypeEnabled(String apnType) { 1026 if (apnType == null) { 1027 return false; 1028 } else { 1029 return isApnIdEnabled(apnTypeToId(apnType)); 1030 } 1031 } 1032 1033 protected synchronized boolean isApnIdEnabled(int id) { 1034 if (id != DctConstants.APN_INVALID_ID) { 1035 return mDataEnabled[id]; 1036 } 1037 return false; 1038 } 1039 1040 /** 1041 * Ensure that we are connected to an APN of the specified type. 1042 * 1043 * @param type the APN type (currently the only valid values are 1044 * {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL}) 1045 * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or 1046 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a 1047 * broadcast will be sent by the ConnectivityManager when a 1048 * connection to the APN has been established. 1049 */ 1050 public synchronized int enableApnType(String type) { 1051 int id = apnTypeToId(type); 1052 if (id == DctConstants.APN_INVALID_ID) { 1053 return PhoneConstants.APN_REQUEST_FAILED; 1054 } 1055 1056 if (DBG) { 1057 log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type) 1058 + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState); 1059 } 1060 1061 if (!isApnTypeAvailable(type)) { 1062 if (DBG) log("enableApnType: not available, type=" + type); 1063 return PhoneConstants.APN_TYPE_NOT_AVAILABLE; 1064 } 1065 1066 if (isApnIdEnabled(id)) { 1067 if (DBG) log("enableApnType: already active, type=" + type); 1068 return PhoneConstants.APN_ALREADY_ACTIVE; 1069 } else { 1070 setEnabled(id, true); 1071 } 1072 return PhoneConstants.APN_REQUEST_STARTED; 1073 } 1074 1075 /** 1076 * The APN of the specified type is no longer needed. Ensure that if use of 1077 * the default APN has not been explicitly disabled, we are connected to the 1078 * default APN. 1079 * 1080 * @param type the APN type. The only valid values are currently 1081 * {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL}. 1082 * @return Success is indicated by {@code PhoneConstants.APN_ALREADY_ACTIVE} or 1083 * {@code PhoneConstants.APN_REQUEST_STARTED}. In the latter case, a 1084 * broadcast will be sent by the ConnectivityManager when a 1085 * connection to the APN has been disconnected. A {@code 1086 * PhoneConstants.APN_REQUEST_FAILED} is returned if the type parameter is 1087 * invalid or if the apn wasn't enabled. 1088 */ 1089 public synchronized int disableApnType(String type) { 1090 if (DBG) log("disableApnType(" + type + ")"); 1091 int id = apnTypeToId(type); 1092 if (id == DctConstants.APN_INVALID_ID) { 1093 return PhoneConstants.APN_REQUEST_FAILED; 1094 } 1095 if (isApnIdEnabled(id)) { 1096 setEnabled(id, false); 1097 if (isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) { 1098 if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) { 1099 return PhoneConstants.APN_ALREADY_ACTIVE; 1100 } else { 1101 return PhoneConstants.APN_REQUEST_STARTED; 1102 } 1103 } else { 1104 return PhoneConstants.APN_REQUEST_STARTED; 1105 } 1106 } else { 1107 return PhoneConstants.APN_REQUEST_FAILED; 1108 } 1109 } 1110 1111 protected void setEnabled(int id, boolean enable) { 1112 if (DBG) { 1113 log("setEnabled(" + id + ", " + enable + ") with old state = " + mDataEnabled[id] 1114 + " and enabledCount = " + mEnabledCount); 1115 } 1116 Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN); 1117 msg.arg1 = id; 1118 msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 1119 sendMessage(msg); 1120 } 1121 1122 protected void onEnableApn(int apnId, int enabled) { 1123 if (DBG) { 1124 log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) + 1125 ", enabled=" + enabled + ", dataEnabled = " + mDataEnabled[apnId] + 1126 ", enabledCount = " + mEnabledCount + ", isApnTypeActive = " + 1127 isApnTypeActive(apnIdToType(apnId))); 1128 } 1129 if (enabled == DctConstants.ENABLED) { 1130 synchronized (this) { 1131 if (!mDataEnabled[apnId]) { 1132 mDataEnabled[apnId] = true; 1133 mEnabledCount++; 1134 } 1135 } 1136 String type = apnIdToType(apnId); 1137 if (!isApnTypeActive(type)) { 1138 mRequestedApnType = type; 1139 onEnableNewApn(); 1140 } else { 1141 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId); 1142 } 1143 } else { 1144 // disable 1145 boolean didDisable = false; 1146 synchronized (this) { 1147 if (mDataEnabled[apnId]) { 1148 mDataEnabled[apnId] = false; 1149 mEnabledCount--; 1150 didDisable = true; 1151 } 1152 } 1153 if (didDisable) { 1154 if ((mEnabledCount == 0) || (apnId == DctConstants.APN_DUN_ID)) { 1155 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 1156 onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED); 1157 } 1158 1159 // send the disconnect msg manually, since the normal route wont send 1160 // it (it's not enabled) 1161 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId); 1162 if (mDataEnabled[DctConstants.APN_DEFAULT_ID] == true 1163 && !isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) { 1164 // TODO - this is an ugly way to restore the default conn - should be done 1165 // by a real contention manager and policy that disconnects the lower pri 1166 // stuff as enable requests come in and pops them back on as we disable back 1167 // down to the lower pri stuff 1168 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 1169 onEnableNewApn(); 1170 } 1171 } 1172 } 1173 } 1174 1175 /** 1176 * Called when we switch APNs. 1177 * 1178 * mRequestedApnType is set prior to call 1179 * To be overridden. 1180 */ 1181 protected void onEnableNewApn() { 1182 } 1183 1184 /** 1185 * Called when EVENT_RESET_DONE is received so goto 1186 * IDLE state and send notifications to those interested. 1187 * 1188 * TODO - currently unused. Needs to be hooked into DataConnection cleanup 1189 * TODO - needs to pass some notion of which connection is reset.. 1190 */ 1191 protected void onResetDone(AsyncResult ar) { 1192 if (DBG) log("EVENT_RESET_DONE"); 1193 String reason = null; 1194 if (ar.userObj instanceof String) { 1195 reason = (String) ar.userObj; 1196 } 1197 gotoIdleAndNotifyDataConnection(reason); 1198 } 1199 1200 /** 1201 * Prevent mobile data connections from being established, or once again 1202 * allow mobile data connections. If the state toggles, then either tear 1203 * down or set up data, as appropriate to match the new state. 1204 * 1205 * @param enable indicates whether to enable ({@code true}) or disable ( 1206 * {@code false}) data 1207 * @return {@code true} if the operation succeeded 1208 */ 1209 public boolean setInternalDataEnabled(boolean enable) { 1210 if (DBG) 1211 log("setInternalDataEnabled(" + enable + ")"); 1212 1213 Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE); 1214 msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 1215 sendMessage(msg); 1216 return true; 1217 } 1218 1219 protected void onSetInternalDataEnabled(boolean enabled) { 1220 synchronized (mDataEnabledLock) { 1221 mInternalDataEnabled = enabled; 1222 if (enabled) { 1223 log("onSetInternalDataEnabled: changed to enabled, try to setup data call"); 1224 onTrySetupData(Phone.REASON_DATA_ENABLED); 1225 } else { 1226 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections"); 1227 cleanUpAllConnections(null); 1228 } 1229 } 1230 } 1231 1232 public void cleanUpAllConnections(String cause) { 1233 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); 1234 msg.obj = cause; 1235 sendMessage(msg); 1236 } 1237 1238 public abstract boolean isDisconnected(); 1239 1240 protected void onSetUserDataEnabled(boolean enabled) { 1241 synchronized (mDataEnabledLock) { 1242 final boolean prevEnabled = getAnyDataEnabled(); 1243 if (mUserDataEnabled != enabled) { 1244 mUserDataEnabled = enabled; 1245 Settings.Global.putInt(mPhone.getContext().getContentResolver(), 1246 Settings.Global.MOBILE_DATA, enabled ? 1 : 0); 1247 if (getDataOnRoamingEnabled() == false && 1248 mPhone.getServiceState().getRoaming() == true) { 1249 if (enabled) { 1250 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON); 1251 } else { 1252 notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED); 1253 } 1254 } 1255 if (prevEnabled != getAnyDataEnabled()) { 1256 if (!prevEnabled) { 1257 onTrySetupData(Phone.REASON_DATA_ENABLED); 1258 } else { 1259 onCleanUpAllConnections(Phone.REASON_DATA_DISABLED); 1260 } 1261 } 1262 } 1263 } 1264 } 1265 1266 protected void onSetDependencyMet(String apnType, boolean met) { 1267 } 1268 1269 protected void onSetPolicyDataEnabled(boolean enabled) { 1270 synchronized (mDataEnabledLock) { 1271 final boolean prevEnabled = getAnyDataEnabled(); 1272 if (sPolicyDataEnabled != enabled) { 1273 sPolicyDataEnabled = enabled; 1274 if (prevEnabled != getAnyDataEnabled()) { 1275 if (!prevEnabled) { 1276 onTrySetupData(Phone.REASON_DATA_ENABLED); 1277 } else { 1278 onCleanUpAllConnections(Phone.REASON_DATA_DISABLED); 1279 } 1280 } 1281 } 1282 } 1283 } 1284 1285 protected String getReryConfig(boolean forDefault) { 1286 int nt = mPhone.getServiceState().getNetworkType(); 1287 1288 if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) || 1289 (nt == TelephonyManager.NETWORK_TYPE_1xRTT) || 1290 (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) || 1291 (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) || 1292 (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) || 1293 (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) { 1294 // CDMA variant 1295 return SystemProperties.get("ro.cdma.data_retry_config"); 1296 } else { 1297 // Use GSM varient for all others. 1298 if (forDefault) { 1299 return SystemProperties.get("ro.gsm.data_retry_config"); 1300 } else { 1301 return SystemProperties.get("ro.gsm.2nd_data_retry_config"); 1302 } 1303 } 1304 } 1305 1306 protected void resetPollStats() { 1307 mTxPkts = -1; 1308 mRxPkts = -1; 1309 mNetStatPollPeriod = POLL_NETSTAT_MILLIS; 1310 } 1311 1312 protected abstract DctConstants.State getOverallState(); 1313 1314 protected void startNetStatPoll() { 1315 if (getOverallState() == DctConstants.State.CONNECTED 1316 && mNetStatPollEnabled == false) { 1317 if (DBG) log("startNetStatPoll"); 1318 resetPollStats(); 1319 mNetStatPollEnabled = true; 1320 mPollNetStat.run(); 1321 } 1322 } 1323 1324 protected void stopNetStatPoll() { 1325 mNetStatPollEnabled = false; 1326 removeCallbacks(mPollNetStat); 1327 if (DBG) log("stopNetStatPoll"); 1328 } 1329 1330 public void updateDataActivity() { 1331 long sent, received; 1332 1333 DctConstants.Activity newActivity; 1334 1335 TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); 1336 TxRxSum curTxRxSum = new TxRxSum(); 1337 curTxRxSum.updateTxRxSum(); 1338 mTxPkts = curTxRxSum.txPkts; 1339 mRxPkts = curTxRxSum.rxPkts; 1340 1341 if (VDBG) { 1342 log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); 1343 } 1344 1345 if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { 1346 sent = mTxPkts - preTxRxSum.txPkts; 1347 received = mRxPkts - preTxRxSum.rxPkts; 1348 1349 if (VDBG) 1350 log("updateDataActivity: sent=" + sent + " received=" + received); 1351 if (sent > 0 && received > 0) { 1352 newActivity = DctConstants.Activity.DATAINANDOUT; 1353 } else if (sent > 0 && received == 0) { 1354 newActivity = DctConstants.Activity.DATAOUT; 1355 } else if (sent == 0 && received > 0) { 1356 newActivity = DctConstants.Activity.DATAIN; 1357 } else { 1358 newActivity = (mActivity == DctConstants.Activity.DORMANT) ? 1359 mActivity : DctConstants.Activity.NONE; 1360 } 1361 1362 if (mActivity != newActivity && mIsScreenOn) { 1363 if (VDBG) 1364 log("updateDataActivity: newActivity=" + newActivity); 1365 mActivity = newActivity; 1366 mPhone.notifyDataActivity(); 1367 } 1368 } 1369 } 1370 1371 // Recovery action taken in case of data stall 1372 protected static class RecoveryAction { 1373 public static final int GET_DATA_CALL_LIST = 0; 1374 public static final int CLEANUP = 1; 1375 public static final int REREGISTER = 2; 1376 public static final int RADIO_RESTART = 3; 1377 public static final int RADIO_RESTART_WITH_PROP = 4; 1378 1379 private static boolean isAggressiveRecovery(int value) { 1380 return ((value == RecoveryAction.CLEANUP) || 1381 (value == RecoveryAction.REREGISTER) || 1382 (value == RecoveryAction.RADIO_RESTART) || 1383 (value == RecoveryAction.RADIO_RESTART_WITH_PROP)); 1384 } 1385 } 1386 1387 public int getRecoveryAction() { 1388 int action = Settings.System.getInt(mPhone.getContext().getContentResolver(), 1389 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST); 1390 if (VDBG_STALL) log("getRecoveryAction: " + action); 1391 return action; 1392 } 1393 public void putRecoveryAction(int action) { 1394 Settings.System.putInt(mPhone.getContext().getContentResolver(), 1395 "radio.data.stall.recovery.action", action); 1396 if (VDBG_STALL) log("putRecoveryAction: " + action); 1397 } 1398 1399 protected boolean isConnected() { 1400 return false; 1401 } 1402 1403 protected void doRecovery() { 1404 if (getOverallState() == DctConstants.State.CONNECTED) { 1405 // Go through a series of recovery steps, each action transitions to the next action 1406 int recoveryAction = getRecoveryAction(); 1407 switch (recoveryAction) { 1408 case RecoveryAction.GET_DATA_CALL_LIST: 1409 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, 1410 mSentSinceLastRecv); 1411 if (DBG) log("doRecovery() get data call list"); 1412 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED)); 1413 putRecoveryAction(RecoveryAction.CLEANUP); 1414 break; 1415 case RecoveryAction.CLEANUP: 1416 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv); 1417 if (DBG) log("doRecovery() cleanup all connections"); 1418 cleanUpAllConnections(Phone.REASON_PDP_RESET); 1419 putRecoveryAction(RecoveryAction.REREGISTER); 1420 break; 1421 case RecoveryAction.REREGISTER: 1422 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, 1423 mSentSinceLastRecv); 1424 if (DBG) log("doRecovery() re-register"); 1425 mPhone.getServiceStateTracker().reRegisterNetwork(null); 1426 putRecoveryAction(RecoveryAction.RADIO_RESTART); 1427 break; 1428 case RecoveryAction.RADIO_RESTART: 1429 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, 1430 mSentSinceLastRecv); 1431 if (DBG) log("restarting radio"); 1432 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP); 1433 restartRadio(); 1434 break; 1435 case RecoveryAction.RADIO_RESTART_WITH_PROP: 1436 // This is in case radio restart has not recovered the data. 1437 // It will set an additional "gsm.radioreset" property to tell 1438 // RIL or system to take further action. 1439 // The implementation of hard reset recovery action is up to OEM product. 1440 // Once RADIO_RESET property is consumed, it is expected to set back 1441 // to false by RIL. 1442 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1); 1443 if (DBG) log("restarting radio with gsm.radioreset to true"); 1444 SystemProperties.set(RADIO_RESET_PROPERTY, "true"); 1445 // give 1 sec so property change can be notified. 1446 try { 1447 Thread.sleep(1000); 1448 } catch (InterruptedException e) {} 1449 restartRadio(); 1450 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1451 break; 1452 default: 1453 throw new RuntimeException("doRecovery: Invalid recoveryAction=" + 1454 recoveryAction); 1455 } 1456 mSentSinceLastRecv = 0; 1457 } 1458 } 1459 1460 private void updateDataStallInfo() { 1461 long sent, received; 1462 1463 TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); 1464 mDataStallTxRxSum.updateTxRxSum(); 1465 1466 if (VDBG_STALL) { 1467 log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + 1468 " preTxRxSum=" + preTxRxSum); 1469 } 1470 1471 sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; 1472 received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; 1473 1474 if (RADIO_TESTS) { 1475 if (SystemProperties.getBoolean("radio.test.data.stall", false)) { 1476 log("updateDataStallInfo: radio.test.data.stall true received = 0;"); 1477 received = 0; 1478 } 1479 } 1480 if ( sent > 0 && received > 0 ) { 1481 if (VDBG_STALL) log("updateDataStallInfo: IN/OUT"); 1482 mSentSinceLastRecv = 0; 1483 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1484 } else if (sent > 0 && received == 0) { 1485 if (mPhone.getState() == PhoneConstants.State.IDLE) { 1486 mSentSinceLastRecv += sent; 1487 } else { 1488 mSentSinceLastRecv = 0; 1489 } 1490 if (DBG) { 1491 log("updateDataStallInfo: OUT sent=" + sent + 1492 " mSentSinceLastRecv=" + mSentSinceLastRecv); 1493 } 1494 } else if (sent == 0 && received > 0) { 1495 if (VDBG_STALL) log("updateDataStallInfo: IN"); 1496 mSentSinceLastRecv = 0; 1497 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 1498 } else { 1499 if (VDBG_STALL) log("updateDataStallInfo: NONE"); 1500 } 1501 } 1502 1503 protected void onDataStallAlarm(int tag) { 1504 if (mDataStallAlarmTag != tag) { 1505 if (DBG) { 1506 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); 1507 } 1508 return; 1509 } 1510 updateDataStallInfo(); 1511 1512 int hangWatchdogTrigger = Settings.Global.getInt(mResolver, 1513 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, 1514 NUMBER_SENT_PACKETS_OF_HANG); 1515 1516 boolean suspectedStall = DATA_STALL_NOT_SUSPECTED; 1517 if (mSentSinceLastRecv >= hangWatchdogTrigger) { 1518 if (DBG) { 1519 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction()); 1520 } 1521 suspectedStall = DATA_STALL_SUSPECTED; 1522 sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); 1523 } else { 1524 if (VDBG_STALL) { 1525 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + 1526 " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); 1527 } 1528 } 1529 startDataStallAlarm(suspectedStall); 1530 } 1531 1532 protected void startDataStallAlarm(boolean suspectedStall) { 1533 int nextAction = getRecoveryAction(); 1534 int delayInMs; 1535 1536 if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) { 1537 // If screen is on or data stall is currently suspected, set the alarm 1538 // with an aggresive timeout. 1539 if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) { 1540 delayInMs = Settings.Global.getInt(mResolver, 1541 Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, 1542 DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT); 1543 } else { 1544 delayInMs = Settings.Global.getInt(mResolver, 1545 Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, 1546 DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT); 1547 } 1548 1549 mDataStallAlarmTag += 1; 1550 if (VDBG_STALL) { 1551 log("startDataStallAlarm: tag=" + mDataStallAlarmTag + 1552 " delay=" + (delayInMs / 1000) + "s"); 1553 } 1554 Intent intent = new Intent(INTENT_DATA_STALL_ALARM); 1555 intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag); 1556 mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, 1557 PendingIntent.FLAG_UPDATE_CURRENT); 1558 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1559 SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); 1560 } else { 1561 if (VDBG_STALL) { 1562 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag); 1563 } 1564 } 1565 } 1566 1567 protected void stopDataStallAlarm() { 1568 if (VDBG_STALL) { 1569 log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + 1570 " mDataStallAlarmIntent=" + mDataStallAlarmIntent); 1571 } 1572 mDataStallAlarmTag += 1; 1573 if (mDataStallAlarmIntent != null) { 1574 mAlarmManager.cancel(mDataStallAlarmIntent); 1575 mDataStallAlarmIntent = null; 1576 } 1577 } 1578 1579 protected void restartDataStallAlarm() { 1580 if (isConnected() == false) return; 1581 // To be called on screen status change. 1582 // Do not cancel the alarm if it is set with aggressive timeout. 1583 int nextAction = getRecoveryAction(); 1584 1585 if (RecoveryAction.isAggressiveRecovery(nextAction)) { 1586 if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm."); 1587 return; 1588 } 1589 if (VDBG_STALL) log("restartDataStallAlarm: stop then start."); 1590 stopDataStallAlarm(); 1591 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 1592 } 1593 1594 void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) { 1595 if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext); 1596 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION); 1597 msg.arg1 = tearDown ? 1 : 0; 1598 msg.arg2 = 0; 1599 msg.obj = apnContext; 1600 sendMessage(msg); 1601 } 1602 1603 void sendRestartRadio() { 1604 if (DBG)log("sendRestartRadio:"); 1605 Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO); 1606 sendMessage(msg); 1607 } 1608 1609 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1610 pw.println("DataConnectionTrackerBase:"); 1611 pw.println(" RADIO_TESTS=" + RADIO_TESTS); 1612 pw.println(" mInternalDataEnabled=" + mInternalDataEnabled); 1613 pw.println(" mUserDataEnabled=" + mUserDataEnabled); 1614 pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled); 1615 pw.println(" mDataEnabled:"); 1616 for(int i=0; i < mDataEnabled.length; i++) { 1617 pw.printf(" mDataEnabled[%d]=%b\n", i, mDataEnabled[i]); 1618 } 1619 pw.flush(); 1620 pw.println(" mEnabledCount=" + mEnabledCount); 1621 pw.println(" mRequestedApnType=" + mRequestedApnType); 1622 pw.println(" mPhone=" + mPhone.getPhoneName()); 1623 pw.println(" mActivity=" + mActivity); 1624 pw.println(" mState=" + mState); 1625 pw.println(" mTxPkts=" + mTxPkts); 1626 pw.println(" mRxPkts=" + mRxPkts); 1627 pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod); 1628 pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled); 1629 pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum); 1630 pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag); 1631 pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled); 1632 pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv); 1633 pw.println(" mNoRecvPollCount=" + mNoRecvPollCount); 1634 pw.println(" mResolver=" + mResolver); 1635 pw.println(" mIsWifiConnected=" + mIsWifiConnected); 1636 pw.println(" mReconnectIntent=" + mReconnectIntent); 1637 pw.println(" mCidActive=" + mCidActive); 1638 pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation); 1639 pw.println(" mIsScreenOn=" + mIsScreenOn); 1640 pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); 1641 pw.flush(); 1642 pw.println(" ***************************************"); 1643 DcController dcc = mDcc; 1644 if (dcc != null) { 1645 dcc.dump(fd, pw, args); 1646 } else { 1647 pw.println(" mDcc=null"); 1648 } 1649 pw.println(" ***************************************"); 1650 HashMap<Integer, DataConnection> dcs = mDataConnections; 1651 if (dcs != null) { 1652 Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet(); 1653 pw.println(" mDataConnections: count=" + mDcSet.size()); 1654 for (Entry<Integer, DataConnection> entry : mDcSet) { 1655 pw.printf(" *** mDataConnection[%d] \n", entry.getKey()); 1656 entry.getValue().dump(fd, pw, args); 1657 } 1658 } else { 1659 pw.println("mDataConnections=null"); 1660 } 1661 pw.println(" ***************************************"); 1662 pw.flush(); 1663 HashMap<String, Integer> apnToDcId = mApnToDataConnectionId; 1664 if (apnToDcId != null) { 1665 Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet(); 1666 pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size()); 1667 for (Entry<String, Integer> entry : apnToDcIdSet) { 1668 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue()); 1669 } 1670 } else { 1671 pw.println("mApnToDataConnectionId=null"); 1672 } 1673 pw.println(" ***************************************"); 1674 pw.flush(); 1675 ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts; 1676 if (apnCtxs != null) { 1677 Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet(); 1678 pw.println(" mApnContexts size=" + apnCtxsSet.size()); 1679 for (Entry<String, ApnContext> entry : apnCtxsSet) { 1680 entry.getValue().dump(fd, pw, args); 1681 } 1682 pw.println(" ***************************************"); 1683 } else { 1684 pw.println(" mApnContexts=null"); 1685 } 1686 pw.flush(); 1687 pw.println(" mActiveApn=" + mActiveApn); 1688 ArrayList<ApnSetting> apnSettings = mAllApnSettings; 1689 if (apnSettings != null) { 1690 pw.println(" mAllApnSettings size=" + apnSettings.size()); 1691 for (int i=0; i < apnSettings.size(); i++) { 1692 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i)); 1693 } 1694 pw.flush(); 1695 } else { 1696 pw.println(" mAllApnSettings=null"); 1697 } 1698 pw.println(" mPreferredApn=" + mPreferredApn); 1699 pw.println(" mIsPsRestricted=" + mIsPsRestricted); 1700 pw.println(" mIsDisposed=" + mIsDisposed); 1701 pw.println(" mIntentReceiver=" + mIntentReceiver); 1702 pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver); 1703 pw.flush(); 1704 } 1705 } 1706