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