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