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