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