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