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