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