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