DcTracker.java revision da21f0de2087657b20b18817b33d59778720bffb
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.app.ProgressDialog; 22import android.content.ActivityNotFoundException; 23import android.content.BroadcastReceiver; 24import android.content.ContentResolver; 25import android.content.ContentValues; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.SharedPreferences; 30import android.content.res.Resources; 31import android.database.ContentObserver; 32import android.database.Cursor; 33import android.net.ConnectivityManager; 34import android.net.LinkProperties; 35import android.net.NetworkCapabilities; 36import android.net.NetworkConfig; 37import android.net.NetworkInfo; 38import android.net.NetworkRequest; 39import android.net.NetworkUtils; 40import android.net.ProxyInfo; 41import android.net.TrafficStats; 42import android.net.Uri; 43import android.net.wifi.WifiManager; 44import android.os.AsyncResult; 45import android.os.Build; 46import android.os.Bundle; 47import android.os.Handler; 48import android.os.HandlerThread; 49import android.os.Message; 50import android.os.PersistableBundle; 51import android.os.RegistrantList; 52import android.os.ServiceManager; 53import android.os.SystemClock; 54import android.os.SystemProperties; 55import android.preference.PreferenceManager; 56import android.provider.Settings; 57import android.provider.Settings.SettingNotFoundException; 58import android.provider.Telephony; 59import android.telephony.CarrierConfigManager; 60import android.telephony.CellLocation; 61import android.telephony.PcoData; 62import android.telephony.Rlog; 63import android.telephony.ServiceState; 64import android.telephony.SubscriptionManager; 65import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 66import android.telephony.TelephonyManager; 67import android.telephony.cdma.CdmaCellLocation; 68import android.telephony.gsm.GsmCellLocation; 69import android.text.TextUtils; 70import android.util.EventLog; 71import android.util.LocalLog; 72import android.util.Pair; 73import android.util.SparseArray; 74import android.view.WindowManager; 75 76import com.android.internal.R; 77import com.android.internal.annotations.VisibleForTesting; 78import com.android.internal.telephony.CarrierActionAgent; 79import com.android.internal.telephony.DctConstants; 80import com.android.internal.telephony.EventLogTags; 81import com.android.internal.telephony.GsmCdmaPhone; 82import com.android.internal.telephony.ITelephony; 83import com.android.internal.telephony.Phone; 84import com.android.internal.telephony.PhoneConstants; 85import com.android.internal.telephony.PhoneFactory; 86import com.android.internal.telephony.RILConstants; 87import com.android.internal.telephony.SettingsObserver; 88import com.android.internal.telephony.TelephonyIntents; 89import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType; 90import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; 91import com.android.internal.telephony.metrics.TelephonyMetrics; 92import com.android.internal.telephony.uicc.IccRecords; 93import com.android.internal.telephony.uicc.UiccController; 94import com.android.internal.util.ArrayUtils; 95import com.android.internal.util.AsyncChannel; 96 97import java.io.FileDescriptor; 98import java.io.PrintWriter; 99import java.util.ArrayList; 100import java.util.Arrays; 101import java.util.Comparator; 102import java.util.HashMap; 103import java.util.Map.Entry; 104import java.util.PriorityQueue; 105import java.util.Set; 106import java.util.concurrent.ConcurrentHashMap; 107import java.util.concurrent.atomic.AtomicBoolean; 108import java.util.concurrent.atomic.AtomicInteger; 109import java.util.concurrent.atomic.AtomicReference; 110/** 111 * {@hide} 112 */ 113public class DcTracker extends Handler { 114 private static final String LOG_TAG = "DCT"; 115 private static final boolean DBG = true; 116 private static final boolean VDBG = false; // STOPSHIP if true 117 private static final boolean VDBG_STALL = false; // STOPSHIP if true 118 private static final boolean RADIO_TESTS = false; 119 120 public AtomicBoolean isCleanupRequired = new AtomicBoolean(false); 121 122 private final AlarmManager mAlarmManager; 123 124 /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ 125 private String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 126 127 // All data enabling/disabling related settings 128 private final DataEnabledSettings mDataEnabledSettings = new DataEnabledSettings(); 129 130 131 /** 132 * After detecting a potential connection problem, this is the max number 133 * of subsequent polls before attempting recovery. 134 */ 135 // 1 sec. default polling interval when screen is on. 136 private static final int POLL_NETSTAT_MILLIS = 1000; 137 // 10 min. default polling interval when screen is off. 138 private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; 139 // Default sent packets without ack which triggers initial recovery steps 140 private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; 141 142 // Default for the data stall alarm while non-aggressive stall detection 143 private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; 144 // Default for the data stall alarm for aggressive stall detection 145 private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; 146 // Tag for tracking stale alarms 147 private static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag"; 148 149 private static final boolean DATA_STALL_SUSPECTED = true; 150 private static final boolean DATA_STALL_NOT_SUSPECTED = false; 151 152 private String RADIO_RESET_PROPERTY = "gsm.radioreset"; 153 154 private static final String INTENT_RECONNECT_ALARM = 155 "com.android.internal.telephony.data-reconnect"; 156 private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type"; 157 private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = 158 "reconnect_alarm_extra_reason"; 159 160 private static final String INTENT_DATA_STALL_ALARM = 161 "com.android.internal.telephony.data-stall"; 162 163 private DcTesterFailBringUpAll mDcTesterFailBringUpAll; 164 private DcController mDcc; 165 166 /** kept in sync with mApnContexts 167 * Higher numbers are higher priority and sorted so highest priority is first */ 168 private final PriorityQueue<ApnContext>mPrioritySortedApnContexts = 169 new PriorityQueue<ApnContext>(5, 170 new Comparator<ApnContext>() { 171 public int compare(ApnContext c1, ApnContext c2) { 172 return c2.priority - c1.priority; 173 } 174 } ); 175 176 /** allApns holds all apns */ 177 private ArrayList<ApnSetting> mAllApnSettings = null; 178 179 /** preferred apn */ 180 private ApnSetting mPreferredApn = null; 181 182 /** Is packet service restricted by network */ 183 private boolean mIsPsRestricted = false; 184 185 /** emergency apn Setting*/ 186 private ApnSetting mEmergencyApn = null; 187 188 /* Once disposed dont handle any messages */ 189 private boolean mIsDisposed = false; 190 191 private ContentResolver mResolver; 192 193 /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */ 194 private boolean mIsProvisioning = false; 195 196 /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */ 197 private String mProvisioningUrl = null; 198 199 /* Intent for the provisioning apn alarm */ 200 private static final String INTENT_PROVISIONING_APN_ALARM = 201 "com.android.internal.telephony.provisioning_apn_alarm"; 202 203 /* Tag for tracking stale alarms */ 204 private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag"; 205 206 /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */ 207 private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm"; 208 209 /* Default for the provisioning apn alarm timeout */ 210 private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15; 211 212 /* The provision apn alarm intent used to disable the provisioning apn */ 213 private PendingIntent mProvisioningApnAlarmIntent = null; 214 215 /* Used to track stale provisioning apn alarms */ 216 private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime(); 217 218 private AsyncChannel mReplyAc = new AsyncChannel(); 219 220 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () { 221 @Override 222 public void onReceive(Context context, Intent intent) { 223 String action = intent.getAction(); 224 225 if (action.equals(Intent.ACTION_SCREEN_ON)) { 226 // TODO: Evaluate hooking this up with DeviceStateMonitor 227 if (DBG) log("screen on"); 228 mIsScreenOn = true; 229 stopNetStatPoll(); 230 startNetStatPoll(); 231 restartDataStallAlarm(); 232 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 233 if (DBG) log("screen off"); 234 mIsScreenOn = false; 235 stopNetStatPoll(); 236 startNetStatPoll(); 237 restartDataStallAlarm(); 238 } else if (action.startsWith(INTENT_RECONNECT_ALARM)) { 239 if (DBG) log("Reconnect alarm. Previous state was " + mState); 240 onActionIntentReconnectAlarm(intent); 241 } else if (action.equals(INTENT_DATA_STALL_ALARM)) { 242 if (DBG) log("Data stall alarm"); 243 onActionIntentDataStallAlarm(intent); 244 } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) { 245 if (DBG) log("Provisioning apn alarm"); 246 onActionIntentProvisioningApnAlarm(intent); 247 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 248 final android.net.NetworkInfo networkInfo = (NetworkInfo) 249 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 250 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); 251 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected); 252 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 253 if (DBG) log("Wifi state changed"); 254 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 255 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; 256 if (!enabled) { 257 // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION 258 // quit and won't report disconnected until next enabling. 259 mIsWifiConnected = false; 260 } 261 if (DBG) { 262 log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled 263 + " mIsWifiConnected=" + mIsWifiConnected); 264 } 265 } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 266 if (mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded()) { 267 setDefaultDataRoamingEnabled(); 268 } 269 } else { 270 if (DBG) log("onReceive: Unknown action=" + action); 271 } 272 } 273 }; 274 275 private final Runnable mPollNetStat = new Runnable() { 276 @Override 277 public void run() { 278 updateDataActivity(); 279 280 if (mIsScreenOn) { 281 mNetStatPollPeriod = Settings.Global.getInt(mResolver, 282 Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); 283 } else { 284 mNetStatPollPeriod = Settings.Global.getInt(mResolver, 285 Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, 286 POLL_NETSTAT_SCREEN_OFF_MILLIS); 287 } 288 289 if (mNetStatPollEnabled) { 290 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); 291 } 292 } 293 }; 294 295 private SubscriptionManager mSubscriptionManager; 296 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 297 new OnSubscriptionsChangedListener() { 298 public final AtomicInteger mPreviousSubId = 299 new AtomicInteger(SubscriptionManager.INVALID_SUBSCRIPTION_ID); 300 301 /** 302 * Callback invoked when there is any change to any SubscriptionInfo. Typically 303 * this method invokes {@link SubscriptionManager#getActiveSubscriptionInfoList} 304 */ 305 @Override 306 public void onSubscriptionsChanged() { 307 if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged"); 308 // Set the network type, in case the radio does not restore it. 309 int subId = mPhone.getSubId(); 310 if (SubscriptionManager.isValidSubscriptionId(subId)) { 311 registerSettingsObserver(); 312 } 313 if (mPreviousSubId.getAndSet(subId) != subId && 314 SubscriptionManager.isValidSubscriptionId(subId)) { 315 onRecordsLoadedOrSubIdChanged(); 316 } 317 } 318 }; 319 320 private final SettingsObserver mSettingsObserver; 321 322 private void registerSettingsObserver() { 323 mSettingsObserver.unobserve(); 324 String simSuffix = ""; 325 if (TelephonyManager.getDefault().getSimCount() > 1) { 326 simSuffix = Integer.toString(mPhone.getSubId()); 327 } 328 329 mSettingsObserver.observe( 330 Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix), 331 DctConstants.EVENT_ROAMING_ON); 332 mSettingsObserver.observe( 333 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), 334 DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE); 335 mSettingsObserver.observe( 336 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED), 337 DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE); 338 } 339 340 /** 341 * Maintain the sum of transmit and receive packets. 342 * 343 * The packet counts are initialized and reset to -1 and 344 * remain -1 until they can be updated. 345 */ 346 public static class TxRxSum { 347 public long txPkts; 348 public long rxPkts; 349 350 public TxRxSum() { 351 reset(); 352 } 353 354 public TxRxSum(long txPkts, long rxPkts) { 355 this.txPkts = txPkts; 356 this.rxPkts = rxPkts; 357 } 358 359 public TxRxSum(TxRxSum sum) { 360 txPkts = sum.txPkts; 361 rxPkts = sum.rxPkts; 362 } 363 364 public void reset() { 365 txPkts = -1; 366 rxPkts = -1; 367 } 368 369 @Override 370 public String toString() { 371 return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; 372 } 373 374 public void updateTxRxSum() { 375 this.txPkts = TrafficStats.getMobileTcpTxPackets(); 376 this.rxPkts = TrafficStats.getMobileTcpRxPackets(); 377 } 378 } 379 380 private void onActionIntentReconnectAlarm(Intent intent) { 381 Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT); 382 msg.setData(intent.getExtras()); 383 sendMessage(msg); 384 } 385 386 private void onDataReconnect(Bundle bundle) { 387 String reason = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_REASON); 388 String apnType = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_TYPE); 389 390 int phoneSubId = mPhone.getSubId(); 391 int currSubId = bundle.getInt(PhoneConstants.SUBSCRIPTION_KEY, 392 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 393 log("onDataReconnect: currSubId = " + currSubId + " phoneSubId=" + phoneSubId); 394 395 // Stop reconnect if not current subId is not correct. 396 // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this? 397 if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) { 398 log("receive ReconnectAlarm but subId incorrect, ignore"); 399 return; 400 } 401 402 ApnContext apnContext = mApnContexts.get(apnType); 403 404 if (DBG) { 405 log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType 406 + " apnContext=" + apnContext + " mDataConnectionAsyncChannels=" 407 + mDataConnectionAcHashMap); 408 } 409 410 if ((apnContext != null) && (apnContext.isEnabled())) { 411 apnContext.setReason(reason); 412 DctConstants.State apnContextState = apnContext.getState(); 413 if (DBG) { 414 log("onDataReconnect: apnContext state=" + apnContextState); 415 } 416 if ((apnContextState == DctConstants.State.FAILED) 417 || (apnContextState == DctConstants.State.IDLE)) { 418 if (DBG) { 419 log("onDataReconnect: state is FAILED|IDLE, disassociate"); 420 } 421 DcAsyncChannel dcac = apnContext.getDcAc(); 422 if (dcac != null) { 423 if (DBG) { 424 log("onDataReconnect: tearDown apnContext=" + apnContext); 425 } 426 dcac.tearDown(apnContext, "", null); 427 } 428 apnContext.setDataConnectionAc(null); 429 apnContext.setState(DctConstants.State.IDLE); 430 } else { 431 if (DBG) log("onDataReconnect: keep associated"); 432 } 433 // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA??? 434 sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext)); 435 436 apnContext.setReconnectIntent(null); 437 } 438 } 439 440 private void onActionIntentDataStallAlarm(Intent intent) { 441 if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); 442 Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM, 443 intent.getAction()); 444 msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0); 445 sendMessage(msg); 446 } 447 448 private final ConnectivityManager mCm; 449 450 /** 451 * List of messages that are waiting to be posted, when data call disconnect 452 * is complete 453 */ 454 private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>(); 455 456 private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); 457 458 // member variables 459 private final Phone mPhone; 460 private final UiccController mUiccController; 461 private final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>(); 462 private DctConstants.Activity mActivity = DctConstants.Activity.NONE; 463 private DctConstants.State mState = DctConstants.State.IDLE; 464 private final Handler mDataConnectionTracker; 465 466 private long mTxPkts; 467 private long mRxPkts; 468 private int mNetStatPollPeriod; 469 private boolean mNetStatPollEnabled = false; 470 471 private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); 472 // Used to track stale data stall alarms. 473 private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); 474 // The current data stall alarm intent 475 private PendingIntent mDataStallAlarmIntent = null; 476 // Number of packets sent since the last received packet 477 private long mSentSinceLastRecv; 478 // Controls when a simple recovery attempt it to be tried 479 private int mNoRecvPollCount = 0; 480 // Reference counter for enabling fail fast 481 private static int sEnableFailFastRefCounter = 0; 482 // True if data stall detection is enabled 483 private volatile boolean mDataStallDetectionEnabled = true; 484 485 private volatile boolean mFailFast = false; 486 487 // True when in voice call 488 private boolean mInVoiceCall = false; 489 490 // wifi connection status will be updated by sticky intent 491 private boolean mIsWifiConnected = false; 492 493 /** Intent sent when the reconnect alarm fires. */ 494 private PendingIntent mReconnectIntent = null; 495 496 // When false we will not auto attach and manually attaching is required. 497 private boolean mAutoAttachOnCreationConfig = false; 498 private AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false); 499 500 // State of screen 501 // (TODO: Reconsider tying directly to screen, maybe this is 502 // really a lower power mode") 503 private boolean mIsScreenOn = true; 504 505 // Indicates if we found mvno-specific APNs in the full APN list. 506 // used to determine if we can accept mno-specific APN for tethering. 507 private boolean mMvnoMatched = false; 508 509 /** Allows the generation of unique Id's for DataConnection objects */ 510 private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); 511 512 /** The data connections. */ 513 private HashMap<Integer, DataConnection> mDataConnections = 514 new HashMap<Integer, DataConnection>(); 515 516 /** The data connection async channels */ 517 private HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap = 518 new HashMap<Integer, DcAsyncChannel>(); 519 520 /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ 521 private HashMap<String, Integer> mApnToDataConnectionId = new HashMap<String, Integer>(); 522 523 /** Phone.APN_TYPE_* ===> ApnContext */ 524 private final ConcurrentHashMap<String, ApnContext> mApnContexts = 525 new ConcurrentHashMap<String, ApnContext>(); 526 527 private final SparseArray<ApnContext> mApnContextsById = new SparseArray<ApnContext>(); 528 529 private int mDisconnectPendingCount = 0; 530 531 /** Indicate if metered APNs are disabled. 532 * set to block all the metered APNs from continuously sending requests, which causes 533 * undesired network load */ 534 private boolean mMeteredApnDisabled = false; 535 536 /** 537 * int to remember whether has setDataProfiles and with roaming or not. 538 * 0: default, has never set data profile 539 * 1: has set data profile with home protocol 540 * 2: has set data profile with roaming protocol 541 * This is not needed once RIL command is updated to support both home and roaming protocol. 542 */ 543 private int mSetDataProfileStatus = 0; 544 545 /** 546 * Handles changes to the APN db. 547 */ 548 private class ApnChangeObserver extends ContentObserver { 549 public ApnChangeObserver () { 550 super(mDataConnectionTracker); 551 } 552 553 @Override 554 public void onChange(boolean selfChange) { 555 sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); 556 } 557 } 558 559 //***** Instance Variables 560 561 private boolean mReregisterOnReconnectFailure = false; 562 563 564 //***** Constants 565 566 // Used by puppetmaster/*/radio_stress.py 567 private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active"; 568 569 private static final int POLL_PDP_MILLIS = 5 * 1000; 570 571 private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; 572 573 static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = 574 Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); 575 static final String APN_ID = "apn_id"; 576 577 private boolean mCanSetPreferApn = false; 578 579 private AtomicBoolean mAttached = new AtomicBoolean(false); 580 581 /** Watches for changes to the APN db. */ 582 private ApnChangeObserver mApnObserver; 583 584 private final String mProvisionActionName; 585 private BroadcastReceiver mProvisionBroadcastReceiver; 586 private ProgressDialog mProvisioningSpinner; 587 588 public boolean mImsRegistrationState = false; 589 590 //***** Constructor 591 public DcTracker(Phone phone) { 592 super(); 593 mPhone = phone; 594 595 if (DBG) log("DCT.constructor"); 596 597 mResolver = mPhone.getContext().getContentResolver(); 598 mUiccController = UiccController.getInstance(); 599 mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null); 600 mAlarmManager = 601 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 602 mCm = (ConnectivityManager) mPhone.getContext().getSystemService( 603 Context.CONNECTIVITY_SERVICE); 604 605 606 IntentFilter filter = new IntentFilter(); 607 filter.addAction(Intent.ACTION_SCREEN_ON); 608 filter.addAction(Intent.ACTION_SCREEN_OFF); 609 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 610 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 611 filter.addAction(INTENT_DATA_STALL_ALARM); 612 filter.addAction(INTENT_PROVISIONING_APN_ALARM); 613 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 614 // TODO - redundent with update call below? 615 mDataEnabledSettings.setUserDataEnabled(getDataEnabled()); 616 617 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 618 619 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); 620 mAutoAttachOnCreation.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false)); 621 622 mSubscriptionManager = SubscriptionManager.from(mPhone.getContext()); 623 mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 624 625 HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread"); 626 dcHandlerThread.start(); 627 Handler dcHandler = new Handler(dcHandlerThread.getLooper()); 628 mDcc = DcController.makeDcc(mPhone, this, dcHandler); 629 mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler); 630 631 mDataConnectionTracker = this; 632 registerForAllEvents(); 633 update(); 634 mApnObserver = new ApnChangeObserver(); 635 phone.getContext().getContentResolver().registerContentObserver( 636 Telephony.Carriers.CONTENT_URI, true, mApnObserver); 637 638 initApnContexts(); 639 640 for (ApnContext apnContext : mApnContexts.values()) { 641 // Register the reconnect and restart actions. 642 filter = new IntentFilter(); 643 filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); 644 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 645 } 646 647 // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases 648 initEmergencyApnSetting(); 649 addEmergencyApnSetting(); 650 651 mProvisionActionName = "com.android.internal.telephony.PROVISION" + phone.getPhoneId(); 652 653 mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); 654 registerSettingsObserver(); 655 } 656 657 @VisibleForTesting 658 public DcTracker() { 659 mAlarmManager = null; 660 mCm = null; 661 mPhone = null; 662 mUiccController = null; 663 mDataConnectionTracker = null; 664 mProvisionActionName = null; 665 mSettingsObserver = new SettingsObserver(null, this); 666 } 667 668 public void registerServiceStateTrackerEvents() { 669 mPhone.getServiceStateTracker().registerForDataConnectionAttached(this, 670 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); 671 mPhone.getServiceStateTracker().registerForDataConnectionDetached(this, 672 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); 673 mPhone.getServiceStateTracker().registerForDataRoamingOn(this, 674 DctConstants.EVENT_ROAMING_ON, null); 675 mPhone.getServiceStateTracker().registerForDataRoamingOff(this, 676 DctConstants.EVENT_ROAMING_OFF, null, true); 677 mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, 678 DctConstants.EVENT_PS_RESTRICT_ENABLED, null); 679 mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, 680 DctConstants.EVENT_PS_RESTRICT_DISABLED, null); 681 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this, 682 DctConstants.EVENT_DATA_RAT_CHANGED, null); 683 } 684 685 public void unregisterServiceStateTrackerEvents() { 686 mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this); 687 mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this); 688 mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); 689 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 690 mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); 691 mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); 692 mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(this); 693 } 694 695 private void registerForAllEvents() { 696 mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); 697 mPhone.mCi.registerForOffOrNotAvailable(this, 698 DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 699 mPhone.mCi.registerForDataCallListChanged(this, 700 DctConstants.EVENT_DATA_STATE_CHANGED, null); 701 // Note, this is fragile - the Phone is now presenting a merged picture 702 // of PS (volte) & CS and by diving into its internals you're just seeing 703 // the CS data. This works well for the purposes this is currently used for 704 // but that may not always be the case. Should probably be redesigned to 705 // accurately reflect what we're really interested in (registerForCSVoiceCallEnded). 706 mPhone.getCallTracker().registerForVoiceCallEnded(this, 707 DctConstants.EVENT_VOICE_CALL_ENDED, null); 708 mPhone.getCallTracker().registerForVoiceCallStarted(this, 709 DctConstants.EVENT_VOICE_CALL_STARTED, null); 710 registerServiceStateTrackerEvents(); 711 // SubscriptionManager.registerForDdsSwitch(this, 712 // DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null); 713 mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null); 714 mPhone.getCarrierActionAgent().registerForCarrierAction( 715 CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, this, 716 DctConstants.EVENT_SET_CARRIER_DATA_ENABLED, null, false); 717 } 718 719 public void dispose() { 720 if (DBG) log("DCT.dispose"); 721 722 if (mProvisionBroadcastReceiver != null) { 723 mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); 724 mProvisionBroadcastReceiver = null; 725 } 726 if (mProvisioningSpinner != null) { 727 mProvisioningSpinner.dismiss(); 728 mProvisioningSpinner = null; 729 } 730 731 cleanUpAllConnections(true, null); 732 733 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 734 dcac.disconnect(); 735 } 736 mDataConnectionAcHashMap.clear(); 737 mIsDisposed = true; 738 mPhone.getContext().unregisterReceiver(mIntentReceiver); 739 mUiccController.unregisterForIccChanged(this); 740 mSettingsObserver.unobserve(); 741 742 mSubscriptionManager 743 .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 744 mDcc.dispose(); 745 mDcTesterFailBringUpAll.dispose(); 746 747 mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); 748 mApnContexts.clear(); 749 mApnContextsById.clear(); 750 mPrioritySortedApnContexts.clear(); 751 unregisterForAllEvents(); 752 753 destroyDataConnections(); 754 } 755 756 private void unregisterForAllEvents() { 757 //Unregister for all events 758 mPhone.mCi.unregisterForAvailable(this); 759 mPhone.mCi.unregisterForOffOrNotAvailable(this); 760 IccRecords r = mIccRecords.get(); 761 if (r != null) { 762 r.unregisterForRecordsLoaded(this); 763 mIccRecords.set(null); 764 } 765 mPhone.mCi.unregisterForDataCallListChanged(this); 766 mPhone.getCallTracker().unregisterForVoiceCallEnded(this); 767 mPhone.getCallTracker().unregisterForVoiceCallStarted(this); 768 unregisterServiceStateTrackerEvents(); 769 //SubscriptionManager.unregisterForDdsSwitch(this); 770 mPhone.mCi.unregisterForPcoData(this); 771 mPhone.getCarrierActionAgent().unregisterForCarrierAction(this, 772 CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED); 773 } 774 775 /** 776 * Called when EVENT_RESET_DONE is received so goto 777 * IDLE state and send notifications to those interested. 778 * 779 * TODO - currently unused. Needs to be hooked into DataConnection cleanup 780 * TODO - needs to pass some notion of which connection is reset.. 781 */ 782 private void onResetDone(AsyncResult ar) { 783 if (DBG) log("EVENT_RESET_DONE"); 784 String reason = null; 785 if (ar.userObj instanceof String) { 786 reason = (String) ar.userObj; 787 } 788 gotoIdleAndNotifyDataConnection(reason); 789 } 790 791 /** 792 * Modify {@link android.provider.Settings.Global#MOBILE_DATA} value. 793 */ 794 public void setDataEnabled(boolean enable) { 795 Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE); 796 msg.arg1 = enable ? 1 : 0; 797 if (DBG) log("setDataEnabled: sendMessage: enable=" + enable); 798 sendMessage(msg); 799 } 800 801 private void onSetUserDataEnabled(boolean enabled) { 802 synchronized (mDataEnabledSettings) { 803 if (mDataEnabledSettings.isUserDataEnabled() != enabled) { 804 mDataEnabledSettings.setUserDataEnabled(enabled); 805 806 //TODO: We should move the followings into DataEnabledSettings class. 807 // For single SIM phones, this is a per phone property. 808 if (TelephonyManager.getDefault().getSimCount() == 1) { 809 Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA, enabled ? 1 : 0); 810 } else { 811 int phoneSubId = mPhone.getSubId(); 812 Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA + phoneSubId, 813 enabled ? 1 : 0); 814 } 815 if (!getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { 816 if (enabled) { 817 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON); 818 } else { 819 notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED); 820 } 821 } 822 823 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and 824 // handle the rest from there. 825 if (enabled) { 826 reevaluateDataConnections(); 827 onTrySetupData(Phone.REASON_DATA_ENABLED); 828 } else { 829 onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED); 830 } 831 } 832 } 833 } 834 835 /** 836 * Reevaluate existing data connections when conditions change. 837 * 838 * For example, handle reverting restricted networks back to unrestricted. If we're changing 839 * user data to enabled and this makes data truly enabled (not disabled by other factors) we 840 * need to tear down any metered apn type that was enabled anyway by a privileged request. 841 * This allows us to reconnect to it in an unrestricted way. 842 * 843 * Or when we brought up a unmetered data connection while data is off, we only limit this 844 * data connection for unmetered use only. When data is turned back on, we need to tear that 845 * down so a full capable data connection can be re-established. 846 */ 847 private void reevaluateDataConnections() { 848 if (mDataEnabledSettings.isDataEnabled()) { 849 for (ApnContext apnContext : mApnContexts.values()) { 850 if (apnContext.isConnectedOrConnecting()) { 851 final DcAsyncChannel dcac = apnContext.getDcAc(); 852 if (dcac != null) { 853 final NetworkCapabilities netCaps = dcac.getNetworkCapabilitiesSync(); 854 if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities 855 .NET_CAPABILITY_NOT_RESTRICTED) && !netCaps.hasCapability( 856 NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { 857 if (DBG) { 858 log("Tearing down restricted metered net:" + apnContext); 859 } 860 // Tearing down the restricted metered data call when 861 // conditions change. This will allow reestablishing a new unrestricted 862 // data connection. 863 apnContext.setReason(Phone.REASON_DATA_ENABLED); 864 cleanUpConnection(true, apnContext); 865 } else if (apnContext.getApnSetting().isMetered(mPhone) 866 && (netCaps != null && netCaps.hasCapability( 867 NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) { 868 if (DBG) { 869 log("Tearing down unmetered net:" + apnContext); 870 } 871 // The APN settings is metered, but the data was still marked as 872 // unmetered data, must be the unmetered data connection brought up when 873 // data is off. We need to tear that down when data is enabled again. 874 // This will allow reestablishing a new full capability data connection. 875 apnContext.setReason(Phone.REASON_DATA_ENABLED); 876 cleanUpConnection(true, apnContext); 877 } 878 } 879 } 880 } 881 } 882 } 883 884 private void onDeviceProvisionedChange() { 885 if (getDataEnabled()) { 886 mDataEnabledSettings.setUserDataEnabled(true); 887 reevaluateDataConnections(); 888 onTrySetupData(Phone.REASON_DATA_ENABLED); 889 } else { 890 mDataEnabledSettings.setUserDataEnabled(false); 891 onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED); 892 } 893 } 894 895 896 public long getSubId() { 897 return mPhone.getSubId(); 898 } 899 900 public DctConstants.Activity getActivity() { 901 return mActivity; 902 } 903 904 private void setActivity(DctConstants.Activity activity) { 905 log("setActivity = " + activity); 906 mActivity = activity; 907 mPhone.notifyDataActivity(); 908 } 909 910 public void requestNetwork(NetworkRequest networkRequest, LocalLog log) { 911 final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); 912 final ApnContext apnContext = mApnContextsById.get(apnId); 913 log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext); 914 if (apnContext != null) apnContext.requestNetwork(networkRequest, log); 915 } 916 917 public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) { 918 final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest); 919 final ApnContext apnContext = mApnContextsById.get(apnId); 920 log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext); 921 if (apnContext != null) apnContext.releaseNetwork(networkRequest, log); 922 } 923 924 public boolean isApnSupported(String name) { 925 if (name == null) { 926 loge("isApnSupported: name=null"); 927 return false; 928 } 929 ApnContext apnContext = mApnContexts.get(name); 930 if (apnContext == null) { 931 loge("Request for unsupported mobile name: " + name); 932 return false; 933 } 934 return true; 935 } 936 937 public int getApnPriority(String name) { 938 ApnContext apnContext = mApnContexts.get(name); 939 if (apnContext == null) { 940 loge("Request for unsupported mobile name: " + name); 941 } 942 return apnContext.priority; 943 } 944 945 // Turn telephony radio on or off. 946 private void setRadio(boolean on) { 947 final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 948 try { 949 phone.setRadio(on); 950 } catch (Exception e) { 951 // Ignore. 952 } 953 } 954 955 // Class to handle Intent dispatched with user selects the "Sign-in to network" 956 // notification. 957 private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { 958 private final String mNetworkOperator; 959 // Mobile provisioning URL. Valid while provisioning notification is up. 960 // Set prior to notification being posted as URL contains ICCID which 961 // disappears when radio is off (which is the case when notification is up). 962 private final String mProvisionUrl; 963 964 public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { 965 mNetworkOperator = networkOperator; 966 mProvisionUrl = provisionUrl; 967 } 968 969 private void setEnableFailFastMobileData(int enabled) { 970 sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); 971 } 972 973 private void enableMobileProvisioning() { 974 final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); 975 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl)); 976 sendMessage(msg); 977 } 978 979 @Override 980 public void onReceive(Context context, Intent intent) { 981 // Turning back on the radio can take time on the order of a minute, so show user a 982 // spinner so they know something is going on. 983 log("onReceive : ProvisionNotificationBroadcastReceiver"); 984 mProvisioningSpinner = new ProgressDialog(context); 985 mProvisioningSpinner.setTitle(mNetworkOperator); 986 mProvisioningSpinner.setMessage( 987 // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. 988 context.getText(com.android.internal.R.string.media_route_status_connecting)); 989 mProvisioningSpinner.setIndeterminate(true); 990 mProvisioningSpinner.setCancelable(true); 991 // Allow non-Activity Service Context to create a View. 992 mProvisioningSpinner.getWindow().setType( 993 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 994 mProvisioningSpinner.show(); 995 // After timeout, hide spinner so user can at least use their device. 996 // TODO: Indicate to user that it is taking an unusually long time to connect? 997 sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, 998 mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); 999 // This code is almost identical to the old 1000 // ConnectivityService.handleMobileProvisioningAction code. 1001 setRadio(true); 1002 setEnableFailFastMobileData(DctConstants.ENABLED); 1003 enableMobileProvisioning(); 1004 } 1005 } 1006 1007 @Override 1008 protected void finalize() { 1009 if(DBG && mPhone != null) log("finalize"); 1010 } 1011 1012 private ApnContext addApnContext(String type, NetworkConfig networkConfig) { 1013 ApnContext apnContext = new ApnContext(mPhone, type, LOG_TAG, networkConfig, this); 1014 mApnContexts.put(type, apnContext); 1015 mApnContextsById.put(ApnContext.apnIdForApnName(type), apnContext); 1016 mPrioritySortedApnContexts.add(apnContext); 1017 return apnContext; 1018 } 1019 1020 private void initApnContexts() { 1021 log("initApnContexts: E"); 1022 // Load device network attributes from resources 1023 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray( 1024 com.android.internal.R.array.networkAttributes); 1025 for (String networkConfigString : networkConfigStrings) { 1026 NetworkConfig networkConfig = new NetworkConfig(networkConfigString); 1027 ApnContext apnContext = null; 1028 1029 switch (networkConfig.type) { 1030 case ConnectivityManager.TYPE_MOBILE: 1031 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig); 1032 break; 1033 case ConnectivityManager.TYPE_MOBILE_MMS: 1034 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig); 1035 break; 1036 case ConnectivityManager.TYPE_MOBILE_SUPL: 1037 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig); 1038 break; 1039 case ConnectivityManager.TYPE_MOBILE_DUN: 1040 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig); 1041 break; 1042 case ConnectivityManager.TYPE_MOBILE_HIPRI: 1043 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig); 1044 break; 1045 case ConnectivityManager.TYPE_MOBILE_FOTA: 1046 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig); 1047 break; 1048 case ConnectivityManager.TYPE_MOBILE_IMS: 1049 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig); 1050 break; 1051 case ConnectivityManager.TYPE_MOBILE_CBS: 1052 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig); 1053 break; 1054 case ConnectivityManager.TYPE_MOBILE_IA: 1055 apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig); 1056 break; 1057 case ConnectivityManager.TYPE_MOBILE_EMERGENCY: 1058 apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig); 1059 break; 1060 default: 1061 log("initApnContexts: skipping unknown type=" + networkConfig.type); 1062 continue; 1063 } 1064 log("initApnContexts: apnContext=" + apnContext); 1065 } 1066 1067 if (VDBG) log("initApnContexts: X mApnContexts=" + mApnContexts); 1068 } 1069 1070 public LinkProperties getLinkProperties(String apnType) { 1071 ApnContext apnContext = mApnContexts.get(apnType); 1072 if (apnContext != null) { 1073 DcAsyncChannel dcac = apnContext.getDcAc(); 1074 if (dcac != null) { 1075 if (DBG) log("return link properites for " + apnType); 1076 return dcac.getLinkPropertiesSync(); 1077 } 1078 } 1079 if (DBG) log("return new LinkProperties"); 1080 return new LinkProperties(); 1081 } 1082 1083 public NetworkCapabilities getNetworkCapabilities(String apnType) { 1084 ApnContext apnContext = mApnContexts.get(apnType); 1085 if (apnContext!=null) { 1086 DcAsyncChannel dataConnectionAc = apnContext.getDcAc(); 1087 if (dataConnectionAc != null) { 1088 if (DBG) { 1089 log("get active pdp is not null, return NetworkCapabilities for " + apnType); 1090 } 1091 return dataConnectionAc.getNetworkCapabilitiesSync(); 1092 } 1093 } 1094 if (DBG) log("return new NetworkCapabilities"); 1095 return new NetworkCapabilities(); 1096 } 1097 1098 // Return all active apn types 1099 public String[] getActiveApnTypes() { 1100 if (DBG) log("get all active apn types"); 1101 ArrayList<String> result = new ArrayList<String>(); 1102 1103 for (ApnContext apnContext : mApnContexts.values()) { 1104 if (mAttached.get() && apnContext.isReady()) { 1105 result.add(apnContext.getApnType()); 1106 } 1107 } 1108 1109 return result.toArray(new String[0]); 1110 } 1111 1112 // Return active apn of specific apn type 1113 public String getActiveApnString(String apnType) { 1114 if (VDBG) log( "get active apn string for type:" + apnType); 1115 ApnContext apnContext = mApnContexts.get(apnType); 1116 if (apnContext != null) { 1117 ApnSetting apnSetting = apnContext.getApnSetting(); 1118 if (apnSetting != null) { 1119 return apnSetting.apn; 1120 } 1121 } 1122 return null; 1123 } 1124 1125 // Return state of specific apn type 1126 public DctConstants.State getState(String apnType) { 1127 ApnContext apnContext = mApnContexts.get(apnType); 1128 if (apnContext != null) { 1129 return apnContext.getState(); 1130 } 1131 return DctConstants.State.FAILED; 1132 } 1133 1134 // Return if apn type is a provisioning apn. 1135 private boolean isProvisioningApn(String apnType) { 1136 ApnContext apnContext = mApnContexts.get(apnType); 1137 if (apnContext != null) { 1138 return apnContext.isProvisioningApn(); 1139 } 1140 return false; 1141 } 1142 1143 // Return state of overall 1144 public DctConstants.State getOverallState() { 1145 boolean isConnecting = false; 1146 boolean isFailed = true; // All enabled Apns should be FAILED. 1147 boolean isAnyEnabled = false; 1148 1149 for (ApnContext apnContext : mApnContexts.values()) { 1150 if (apnContext.isEnabled()) { 1151 isAnyEnabled = true; 1152 switch (apnContext.getState()) { 1153 case CONNECTED: 1154 case DISCONNECTING: 1155 if (VDBG) log("overall state is CONNECTED"); 1156 return DctConstants.State.CONNECTED; 1157 case RETRYING: 1158 case CONNECTING: 1159 isConnecting = true; 1160 isFailed = false; 1161 break; 1162 case IDLE: 1163 case SCANNING: 1164 isFailed = false; 1165 break; 1166 default: 1167 isAnyEnabled = true; 1168 break; 1169 } 1170 } 1171 } 1172 1173 if (!isAnyEnabled) { // Nothing enabled. return IDLE. 1174 if (VDBG) log( "overall state is IDLE"); 1175 return DctConstants.State.IDLE; 1176 } 1177 1178 if (isConnecting) { 1179 if (VDBG) log( "overall state is CONNECTING"); 1180 return DctConstants.State.CONNECTING; 1181 } else if (!isFailed) { 1182 if (VDBG) log( "overall state is IDLE"); 1183 return DctConstants.State.IDLE; 1184 } else { 1185 if (VDBG) log( "overall state is FAILED"); 1186 return DctConstants.State.FAILED; 1187 } 1188 } 1189 1190 @VisibleForTesting 1191 public boolean isDataEnabled() { 1192 return mDataEnabledSettings.isDataEnabled(); 1193 } 1194 1195 //****** Called from ServiceStateTracker 1196 /** 1197 * Invoked when ServiceStateTracker observes a transition from GPRS 1198 * attach to detach. 1199 */ 1200 private void onDataConnectionDetached() { 1201 /* 1202 * We presently believe it is unnecessary to tear down the PDP context 1203 * when GPRS detaches, but we should stop the network polling. 1204 */ 1205 if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); 1206 stopNetStatPoll(); 1207 stopDataStallAlarm(); 1208 notifyDataConnection(Phone.REASON_DATA_DETACHED); 1209 mAttached.set(false); 1210 } 1211 1212 private void onDataConnectionAttached() { 1213 if (DBG) log("onDataConnectionAttached"); 1214 mAttached.set(true); 1215 if (getOverallState() == DctConstants.State.CONNECTED) { 1216 if (DBG) log("onDataConnectionAttached: start polling notify attached"); 1217 startNetStatPoll(); 1218 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 1219 notifyDataConnection(Phone.REASON_DATA_ATTACHED); 1220 } else { 1221 // update APN availability so that APN can be enabled. 1222 notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED); 1223 } 1224 if (mAutoAttachOnCreationConfig) { 1225 mAutoAttachOnCreation.set(true); 1226 } 1227 setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED); 1228 } 1229 1230 /** 1231 * Check if it is allowed to make a data connection (without checking APN context specific 1232 * conditions). 1233 * 1234 * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output 1235 * param. It's okay to pass null here and no reasons will be 1236 * provided. 1237 * @return True if data connection is allowed, otherwise false. 1238 */ 1239 public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) { 1240 return isDataAllowed(null, dataConnectionReasons); 1241 } 1242 1243 /** 1244 * Check if it is allowed to make a data connection for a given APN type. 1245 * 1246 * @param apnContext APN context. If passing null, then will only check general but not APN 1247 * specific conditions (e.g. APN state, metered/unmetered APN). 1248 * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output 1249 * param. It's okay to pass null here and no reasons will be 1250 * provided. 1251 * @return True if data connection is allowed, otherwise false. 1252 */ 1253 boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) { 1254 // Step 1: Get all environment conditions. 1255 // Step 2: Special handling for emergency APN. 1256 // Step 3. Build disallowed reasons. 1257 // Step 4: Determine if data should be allowed in some special conditions. 1258 1259 DataConnectionReasons reasons = new DataConnectionReasons(); 1260 1261 // Step 1: Get all environment conditions. 1262 final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled(); 1263 boolean attachedState = mAttached.get(); 1264 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); 1265 boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier(); 1266 // TODO: Remove this hack added by ag/641832. 1267 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 1268 if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { 1269 desiredPowerState = true; 1270 radioStateFromCarrier = true; 1271 } 1272 1273 boolean recordsLoaded = mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded(); 1274 1275 boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId( 1276 SubscriptionManager.getDefaultDataSubscriptionId()); 1277 1278 boolean isMeteredApnType = apnContext == null 1279 || ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone); 1280 1281 PhoneConstants.State phoneState = PhoneConstants.State.IDLE; 1282 // Note this is explicitly not using mPhone.getState. See b/19090488. 1283 // mPhone.getState reports the merge of CS and PS (volte) voice call state 1284 // but we only care about CS calls here for data/voice concurrency issues. 1285 // Calling getCallTracker currently gives you just the CS side where the 1286 // ImsCallTracker is held internally where applicable. 1287 // This should be redesigned to ask explicitly what we want: 1288 // voiceCallStateAllowDataCall, or dataCallAllowed or something similar. 1289 if (mPhone.getCallTracker() != null) { 1290 phoneState = mPhone.getCallTracker().getState(); 1291 } 1292 1293 // Step 2: Special handling for emergency APN. 1294 if (apnContext != null 1295 && apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY) 1296 && apnContext.isConnectable()) { 1297 // If this is an emergency APN, as long as the APN is connectable, we 1298 // should allow it. 1299 if (dataConnectionReasons != null) { 1300 dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN); 1301 } 1302 // Bail out without further checks. 1303 return true; 1304 } 1305 1306 // Step 3. Build disallowed reasons. 1307 if (apnContext != null && !apnContext.isConnectable()) { 1308 reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE); 1309 } 1310 1311 // If RAT is IWLAN then don't allow default/IA PDP at all. 1312 // Rest of APN types can be evaluated for remaining conditions. 1313 if ((apnContext != null && (apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 1314 || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))) 1315 && (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) { 1316 reasons.add(DataDisallowedReasonType.ON_IWLAN); 1317 } 1318 1319 if (isEmergency()) { 1320 reasons.add(DataDisallowedReasonType.IN_ECBM); 1321 } 1322 1323 if (!(attachedState || mAutoAttachOnCreation.get())) { 1324 reasons.add(DataDisallowedReasonType.NOT_ATTACHED); 1325 } 1326 if (!recordsLoaded) { 1327 reasons.add(DataDisallowedReasonType.RECORD_NOT_LOADED); 1328 } 1329 if (phoneState != PhoneConstants.State.IDLE 1330 && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 1331 reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE); 1332 reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED); 1333 } 1334 if (!internalDataEnabled) { 1335 reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED); 1336 } 1337 if (!defaultDataSelected) { 1338 reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED); 1339 } 1340 if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) { 1341 reasons.add(DataDisallowedReasonType.ROAMING_DISABLED); 1342 } 1343 if (mIsPsRestricted) { 1344 reasons.add(DataDisallowedReasonType.PS_RESTRICTED); 1345 } 1346 if (!desiredPowerState) { 1347 reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE); 1348 } 1349 if (!radioStateFromCarrier) { 1350 reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER); 1351 } 1352 if (!mDataEnabledSettings.isDataEnabled()) { 1353 reasons.add(DataDisallowedReasonType.DATA_DISABLED); 1354 } 1355 1356 // If there are hard disallowed reasons, we should not allow data connection no matter what. 1357 if (reasons.containsHardDisallowedReasons()) { 1358 if (dataConnectionReasons != null) { 1359 dataConnectionReasons.copyFrom(reasons); 1360 } 1361 return false; 1362 } 1363 1364 // Step 4: Determine if data should be allowed in some special conditions. 1365 1366 // At this point, if data is not allowed, it must be because of the soft reasons. We 1367 // should start to check some special conditions that data will be allowed. 1368 1369 // If the request APN type is unmetered and there are soft disallowed reasons (e.g. data 1370 // disabled, data roaming disabled) existing, we should allow the data because the user 1371 // won't be charged anyway. 1372 if (!isMeteredApnType && !reasons.allowed()) { 1373 reasons.add(DataAllowedReasonType.UNMETERED_APN); 1374 } 1375 1376 // If the request is restricted and there are only soft disallowed reasons (e.g. data 1377 // disabled, data roaming disabled) existing, we should allow the data. 1378 if (apnContext != null 1379 && !apnContext.hasNoRestrictedRequests(true) 1380 && !reasons.allowed()) { 1381 reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); 1382 } 1383 1384 // If at this point, we still haven't built any disallowed reasons, we should allow data. 1385 if (reasons.allowed()) { 1386 reasons.add(DataAllowedReasonType.NORMAL); 1387 } 1388 1389 if (dataConnectionReasons != null) { 1390 dataConnectionReasons.copyFrom(reasons); 1391 } 1392 1393 return reasons.allowed(); 1394 } 1395 1396 // arg for setupDataOnConnectableApns 1397 private enum RetryFailures { 1398 // retry failed networks always (the old default) 1399 ALWAYS, 1400 // retry only when a substantial change has occurred. Either: 1401 // 1) we were restricted by voice/data concurrency and aren't anymore 1402 // 2) our apn list has change 1403 ONLY_ON_CHANGE 1404 }; 1405 1406 private void setupDataOnConnectableApns(String reason) { 1407 setupDataOnConnectableApns(reason, RetryFailures.ALWAYS); 1408 } 1409 1410 private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) { 1411 if (VDBG) log("setupDataOnConnectableApns: " + reason); 1412 1413 if (DBG && !VDBG) { 1414 StringBuilder sb = new StringBuilder(120); 1415 for (ApnContext apnContext : mPrioritySortedApnContexts) { 1416 sb.append(apnContext.getApnType()); 1417 sb.append(":[state="); 1418 sb.append(apnContext.getState()); 1419 sb.append(",enabled="); 1420 sb.append(apnContext.isEnabled()); 1421 sb.append("] "); 1422 } 1423 log("setupDataOnConnectableApns: " + reason + " " + sb); 1424 } 1425 1426 for (ApnContext apnContext : mPrioritySortedApnContexts) { 1427 if (VDBG) log("setupDataOnConnectableApns: apnContext " + apnContext); 1428 1429 if (apnContext.getState() == DctConstants.State.FAILED 1430 || apnContext.getState() == DctConstants.State.SCANNING) { 1431 if (retryFailures == RetryFailures.ALWAYS) { 1432 apnContext.releaseDataConnection(reason); 1433 } else if (apnContext.isConcurrentVoiceAndDataAllowed() == false && 1434 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 1435 // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed 1436 apnContext.releaseDataConnection(reason); 1437 } 1438 } 1439 if (apnContext.isConnectable()) { 1440 log("isConnectable() call trySetupData"); 1441 apnContext.setReason(reason); 1442 trySetupData(apnContext); 1443 } 1444 } 1445 } 1446 1447 boolean isEmergency() { 1448 final boolean result = mPhone.isInEcm() || mPhone.isInEmergencyCall(); 1449 log("isEmergency: result=" + result); 1450 return result; 1451 } 1452 1453 private boolean trySetupData(ApnContext apnContext) { 1454 1455 if (mPhone.getSimulatedRadioControl() != null) { 1456 // Assume data is connected on the simulator 1457 // FIXME this can be improved 1458 apnContext.setState(DctConstants.State.CONNECTED); 1459 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1460 1461 log("trySetupData: X We're on the simulator; assuming connected retValue=true"); 1462 return true; 1463 } 1464 1465 DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); 1466 boolean isDataAllowed = isDataAllowed(apnContext, dataConnectionReasons); 1467 String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: " 1468 + apnContext.getReason() + ". " + dataConnectionReasons.toString(); 1469 if (DBG) log(logStr); 1470 apnContext.requestLog(logStr); 1471 if (isDataAllowed) { 1472 if (apnContext.getState() == DctConstants.State.FAILED) { 1473 String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable"; 1474 if (DBG) log(str); 1475 apnContext.requestLog(str); 1476 apnContext.setState(DctConstants.State.IDLE); 1477 } 1478 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 1479 apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker() 1480 .isConcurrentVoiceAndDataAllowed()); 1481 if (apnContext.getState() == DctConstants.State.IDLE) { 1482 ArrayList<ApnSetting> waitingApns = 1483 buildWaitingApns(apnContext.getApnType(), radioTech); 1484 if (waitingApns.isEmpty()) { 1485 notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext); 1486 notifyOffApnsOfAvailability(apnContext.getReason()); 1487 String str = "trySetupData: X No APN found retValue=false"; 1488 if (DBG) log(str); 1489 apnContext.requestLog(str); 1490 return false; 1491 } else { 1492 apnContext.setWaitingApns(waitingApns); 1493 if (DBG) { 1494 log ("trySetupData: Create from mAllApnSettings : " 1495 + apnListToString(mAllApnSettings)); 1496 } 1497 } 1498 } 1499 1500 boolean retValue = setupData(apnContext, radioTech, dataConnectionReasons.contains( 1501 DataAllowedReasonType.UNMETERED_APN)); 1502 notifyOffApnsOfAvailability(apnContext.getReason()); 1503 1504 if (DBG) log("trySetupData: X retValue=" + retValue); 1505 return retValue; 1506 } else { 1507 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 1508 && apnContext.isConnectable()) { 1509 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 1510 } 1511 notifyOffApnsOfAvailability(apnContext.getReason()); 1512 1513 StringBuilder str = new StringBuilder(); 1514 1515 str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() 1516 + ", mState=" + apnContext.getState() + ", apnEnabled=" 1517 + apnContext.isEnabled() + ", mDependencyMet=" 1518 + apnContext.getDependencyMet() + "] "); 1519 1520 if (!mDataEnabledSettings.isDataEnabled()) { 1521 str.append("isDataEnabled() = false. " + mDataEnabledSettings); 1522 } 1523 1524 // If this is a data retry, we should set the APN state to FAILED so it won't stay 1525 // in SCANNING forever. 1526 if (apnContext.getState() == DctConstants.State.SCANNING) { 1527 apnContext.setState(DctConstants.State.FAILED); 1528 str.append(" Stop retrying."); 1529 } 1530 1531 if (DBG) log(str.toString()); 1532 apnContext.requestLog(str.toString()); 1533 return false; 1534 } 1535 } 1536 1537 // Disabled apn's still need avail/unavail notifications - send them out 1538 private void notifyOffApnsOfAvailability(String reason) { 1539 for (ApnContext apnContext : mApnContexts.values()) { 1540 if (!mAttached.get() || !apnContext.isReady()) { 1541 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType()); 1542 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 1543 apnContext.getApnType(), 1544 PhoneConstants.DataState.DISCONNECTED); 1545 } else { 1546 if (VDBG) { 1547 log("notifyOffApnsOfAvailability skipped apn due to attached && isReady " + 1548 apnContext.toString()); 1549 } 1550 } 1551 } 1552 } 1553 1554 /** 1555 * If tearDown is true, this only tears down a CONNECTED session. Presently, 1556 * there is no mechanism for abandoning an CONNECTING session, 1557 * but would likely involve cancelling pending async requests or 1558 * setting a flag or new state to ignore them when they came in 1559 * @param tearDown true if the underlying DataConnection should be 1560 * disconnected. 1561 * @param reason reason for the clean up. 1562 * @return boolean - true if we did cleanup any connections, false if they 1563 * were already all disconnected. 1564 */ 1565 private boolean cleanUpAllConnections(boolean tearDown, String reason) { 1566 if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason); 1567 boolean didDisconnect = false; 1568 boolean disableMeteredOnly = false; 1569 1570 // reasons that only metered apn will be torn down 1571 if (!TextUtils.isEmpty(reason)) { 1572 disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) || 1573 reason.equals(Phone.REASON_ROAMING_ON) || 1574 reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); 1575 } 1576 1577 for (ApnContext apnContext : mApnContexts.values()) { 1578 if (apnContext.isDisconnected() == false) didDisconnect = true; 1579 if (disableMeteredOnly) { 1580 // Use ApnSetting to decide metered or non-metered. 1581 // Tear down all metered data connections. 1582 ApnSetting apnSetting = apnContext.getApnSetting(); 1583 if (apnSetting != null && apnSetting.isMetered(mPhone)) { 1584 if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType()); 1585 apnContext.setReason(reason); 1586 cleanUpConnection(tearDown, apnContext); 1587 } 1588 } else { 1589 // TODO - only do cleanup if not disconnected 1590 apnContext.setReason(reason); 1591 cleanUpConnection(tearDown, apnContext); 1592 } 1593 } 1594 1595 stopNetStatPoll(); 1596 stopDataStallAlarm(); 1597 1598 // TODO: Do we need mRequestedApnType? 1599 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 1600 1601 log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount); 1602 if (tearDown && mDisconnectPendingCount == 0) { 1603 notifyDataDisconnectComplete(); 1604 notifyAllDataDisconnected(); 1605 } 1606 1607 return didDisconnect; 1608 } 1609 1610 /** 1611 * Cleanup all connections. 1612 * 1613 * TODO: Cleanup only a specified connection passed as a parameter. 1614 * Also, make sure when you clean up a conn, if it is last apply 1615 * logic as though it is cleanupAllConnections 1616 * 1617 * @param cause for the clean up. 1618 */ 1619 private void onCleanUpAllConnections(String cause) { 1620 cleanUpAllConnections(true, cause); 1621 } 1622 1623 void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) { 1624 if (DBG) log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext); 1625 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION); 1626 msg.arg1 = tearDown ? 1 : 0; 1627 msg.arg2 = 0; 1628 msg.obj = apnContext; 1629 sendMessage(msg); 1630 } 1631 1632 private void cleanUpConnection(boolean tearDown, ApnContext apnContext) { 1633 if (apnContext == null) { 1634 if (DBG) log("cleanUpConnection: apn context is null"); 1635 return; 1636 } 1637 1638 DcAsyncChannel dcac = apnContext.getDcAc(); 1639 String str = "cleanUpConnection: tearDown=" + tearDown + " reason=" + 1640 apnContext.getReason(); 1641 if (VDBG) log(str + " apnContext=" + apnContext); 1642 apnContext.requestLog(str); 1643 if (tearDown) { 1644 if (apnContext.isDisconnected()) { 1645 // The request is tearDown and but ApnContext is not connected. 1646 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. 1647 apnContext.setState(DctConstants.State.IDLE); 1648 if (!apnContext.isReady()) { 1649 if (dcac != null) { 1650 str = "cleanUpConnection: teardown, disconnected, !ready"; 1651 if (DBG) log(str + " apnContext=" + apnContext); 1652 apnContext.requestLog(str); 1653 dcac.tearDown(apnContext, "", null); 1654 } 1655 apnContext.setDataConnectionAc(null); 1656 } 1657 } else { 1658 // Connection is still there. Try to clean up. 1659 if (dcac != null) { 1660 if (apnContext.getState() != DctConstants.State.DISCONNECTING) { 1661 boolean disconnectAll = false; 1662 if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) { 1663 // CAF_MSIM is this below condition required. 1664 // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) { 1665 if (teardownForDun()) { 1666 if (DBG) { 1667 log("cleanUpConnection: disconnectAll DUN connection"); 1668 } 1669 // we need to tear it down - we brought it up just for dun and 1670 // other people are camped on it and now dun is done. We need 1671 // to stop using it and let the normal apn list get used to find 1672 // connections for the remaining desired connections 1673 disconnectAll = true; 1674 } 1675 } 1676 final int generation = apnContext.getConnectionGeneration(); 1677 str = "cleanUpConnection: tearing down" + (disconnectAll ? " all" : "") + 1678 " using gen#" + generation; 1679 if (DBG) log(str + "apnContext=" + apnContext); 1680 apnContext.requestLog(str); 1681 Pair<ApnContext, Integer> pair = 1682 new Pair<ApnContext, Integer>(apnContext, generation); 1683 Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); 1684 if (disconnectAll) { 1685 apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg); 1686 } else { 1687 apnContext.getDcAc() 1688 .tearDown(apnContext, apnContext.getReason(), msg); 1689 } 1690 apnContext.setState(DctConstants.State.DISCONNECTING); 1691 mDisconnectPendingCount++; 1692 } 1693 } else { 1694 // apn is connected but no reference to dcac. 1695 // Should not be happen, but reset the state in case. 1696 apnContext.setState(DctConstants.State.IDLE); 1697 apnContext.requestLog("cleanUpConnection: connected, bug no DCAC"); 1698 mPhone.notifyDataConnection(apnContext.getReason(), 1699 apnContext.getApnType()); 1700 } 1701 } 1702 } else { 1703 // force clean up the data connection. 1704 if (dcac != null) dcac.reqReset(); 1705 apnContext.setState(DctConstants.State.IDLE); 1706 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1707 apnContext.setDataConnectionAc(null); 1708 } 1709 1710 // Make sure reconnection alarm is cleaned up if there is no ApnContext 1711 // associated to the connection. 1712 if (dcac != null) { 1713 cancelReconnectAlarm(apnContext); 1714 } 1715 str = "cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason(); 1716 if (DBG) log(str + " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc()); 1717 apnContext.requestLog(str); 1718 } 1719 1720 /** 1721 * Fetch dun apn 1722 * @return ApnSetting to be used for dun 1723 */ 1724 @VisibleForTesting 1725 public ApnSetting fetchDunApn() { 1726 if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) { 1727 log("fetchDunApn: net.tethering.noprovisioning=true ret: null"); 1728 return null; 1729 } 1730 int bearer = mPhone.getServiceState().getRilDataRadioTechnology(); 1731 IccRecords r = mIccRecords.get(); 1732 String operator = (r != null) ? r.getOperatorNumeric() : ""; 1733 ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>(); 1734 ApnSetting retDunSetting = null; 1735 1736 // Places to look for tether APN in order: TETHER_DUN_APN setting (to be deprecated soon), 1737 // APN database, and config_tether_apndata resource (to be deprecated soon). 1738 String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN); 1739 if (!TextUtils.isEmpty(apnData)) { 1740 dunCandidates.addAll(ApnSetting.arrayFromString(apnData)); 1741 if (VDBG) log("fetchDunApn: dunCandidates from Setting: " + dunCandidates); 1742 } 1743 1744 // todo: remove this and config_tether_apndata after APNs are moved from overlay to apns xml 1745 // If TETHER_DUN_APN isn't set or APN database doesn't have dun APN, 1746 // try the resource as last resort. 1747 if (dunCandidates.isEmpty()) { 1748 String[] apnArrayData = mPhone.getContext().getResources() 1749 .getStringArray(R.array.config_tether_apndata); 1750 if (!ArrayUtils.isEmpty(apnArrayData)) { 1751 for (String apnString : apnArrayData) { 1752 ApnSetting apn = ApnSetting.fromString(apnString); 1753 // apn may be null if apnString isn't valid or has error parsing 1754 if (apn != null) dunCandidates.add(apn); 1755 } 1756 if (VDBG) log("fetchDunApn: dunCandidates from resource: " + dunCandidates); 1757 } 1758 } 1759 1760 if (dunCandidates.isEmpty()) { 1761 if (!ArrayUtils.isEmpty(mAllApnSettings)) { 1762 for (ApnSetting apn : mAllApnSettings) { 1763 if (apn.canHandleType(PhoneConstants.APN_TYPE_DUN)) { 1764 dunCandidates.add(apn); 1765 } 1766 } 1767 if (VDBG) log("fetchDunApn: dunCandidates from database: " + dunCandidates); 1768 } 1769 } 1770 1771 for (ApnSetting dunSetting : dunCandidates) { 1772 if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue; 1773 if (dunSetting.numeric.equals(operator)) { 1774 if (dunSetting.hasMvnoParams()) { 1775 if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType, 1776 dunSetting.mvnoMatchData)) { 1777 retDunSetting = dunSetting; 1778 break; 1779 } 1780 } else if (mMvnoMatched == false) { 1781 retDunSetting = dunSetting; 1782 break; 1783 } 1784 } 1785 } 1786 1787 if (VDBG) log("fetchDunApn: dunSetting=" + retDunSetting); 1788 return retDunSetting; 1789 } 1790 1791 public boolean hasMatchedTetherApnSetting() { 1792 ApnSetting matched = fetchDunApn(); 1793 log("hasMatchedTetherApnSetting: APN=" + matched); 1794 return matched != null; 1795 } 1796 1797 /** 1798 * Determine if DUN connection is special and we need to teardown on start/stop 1799 */ 1800 private boolean teardownForDun() { 1801 // CDMA always needs to do this the profile id is correct 1802 final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology(); 1803 if (ServiceState.isCdma(rilRat)) return true; 1804 1805 return (fetchDunApn() != null); 1806 } 1807 1808 /** 1809 * Cancels the alarm associated with apnContext. 1810 * 1811 * @param apnContext on which the alarm should be stopped. 1812 */ 1813 private void cancelReconnectAlarm(ApnContext apnContext) { 1814 if (apnContext == null) return; 1815 1816 PendingIntent intent = apnContext.getReconnectIntent(); 1817 1818 if (intent != null) { 1819 AlarmManager am = 1820 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1821 am.cancel(intent); 1822 apnContext.setReconnectIntent(null); 1823 } 1824 } 1825 1826 /** 1827 * @param types comma delimited list of APN types 1828 * @return array of APN types 1829 */ 1830 private String[] parseTypes(String types) { 1831 String[] result; 1832 // If unset, set to DEFAULT. 1833 if (types == null || types.equals("")) { 1834 result = new String[1]; 1835 result[0] = PhoneConstants.APN_TYPE_ALL; 1836 } else { 1837 result = types.split(","); 1838 } 1839 return result; 1840 } 1841 1842 boolean isPermanentFailure(DcFailCause dcFailCause) { 1843 return (dcFailCause.isPermanentFailure(mPhone.getContext(), mPhone.getSubId()) && 1844 (mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST)); 1845 } 1846 1847 private ApnSetting makeApnSetting(Cursor cursor) { 1848 String[] types = parseTypes( 1849 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); 1850 ApnSetting apn = new ApnSetting( 1851 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), 1852 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), 1853 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), 1854 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), 1855 NetworkUtils.trimV4AddrZeros( 1856 cursor.getString( 1857 cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), 1858 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), 1859 NetworkUtils.trimV4AddrZeros( 1860 cursor.getString( 1861 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), 1862 NetworkUtils.trimV4AddrZeros( 1863 cursor.getString( 1864 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), 1865 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), 1866 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), 1867 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), 1868 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), 1869 types, 1870 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), 1871 cursor.getString(cursor.getColumnIndexOrThrow( 1872 Telephony.Carriers.ROAMING_PROTOCOL)), 1873 cursor.getInt(cursor.getColumnIndexOrThrow( 1874 Telephony.Carriers.CARRIER_ENABLED)) == 1, 1875 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)), 1876 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER_BITMASK)), 1877 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), 1878 cursor.getInt(cursor.getColumnIndexOrThrow( 1879 Telephony.Carriers.MODEM_COGNITIVE)) == 1, 1880 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), 1881 cursor.getInt(cursor.getColumnIndexOrThrow( 1882 Telephony.Carriers.WAIT_TIME)), 1883 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)), 1884 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), 1885 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE)), 1886 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA))); 1887 return apn; 1888 } 1889 1890 private ArrayList<ApnSetting> createApnList(Cursor cursor) { 1891 ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>(); 1892 ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>(); 1893 IccRecords r = mIccRecords.get(); 1894 1895 if (cursor.moveToFirst()) { 1896 do { 1897 ApnSetting apn = makeApnSetting(cursor); 1898 if (apn == null) { 1899 continue; 1900 } 1901 1902 if (apn.hasMvnoParams()) { 1903 if (r != null && ApnSetting.mvnoMatches(r, apn.mvnoType, apn.mvnoMatchData)) { 1904 mvnoApns.add(apn); 1905 } 1906 } else { 1907 mnoApns.add(apn); 1908 } 1909 } while (cursor.moveToNext()); 1910 } 1911 1912 ArrayList<ApnSetting> result; 1913 if (mvnoApns.isEmpty()) { 1914 result = mnoApns; 1915 mMvnoMatched = false; 1916 } else { 1917 result = mvnoApns; 1918 mMvnoMatched = true; 1919 } 1920 if (DBG) log("createApnList: X result=" + result); 1921 return result; 1922 } 1923 1924 private boolean dataConnectionNotInUse(DcAsyncChannel dcac) { 1925 if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac); 1926 for (ApnContext apnContext : mApnContexts.values()) { 1927 if (apnContext.getDcAc() == dcac) { 1928 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext); 1929 return false; 1930 } 1931 } 1932 // TODO: Fix retry handling so free DataConnections have empty apnlists. 1933 // Probably move retry handling into DataConnections and reduce complexity 1934 // of DCT. 1935 if (DBG) log("dataConnectionNotInUse: tearDownAll"); 1936 dcac.tearDownAll("No connection", null); 1937 if (DBG) log("dataConnectionNotInUse: not in use return true"); 1938 return true; 1939 } 1940 1941 private DcAsyncChannel findFreeDataConnection() { 1942 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 1943 if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) { 1944 if (DBG) { 1945 log("findFreeDataConnection: found free DataConnection=" + 1946 " dcac=" + dcac); 1947 } 1948 return dcac; 1949 } 1950 } 1951 log("findFreeDataConnection: NO free DataConnection"); 1952 return null; 1953 } 1954 1955 /** 1956 * Setup a data connection based on given APN type. 1957 * 1958 * @param apnContext APN context 1959 * @param radioTech RAT of the data connection 1960 * @param unmeteredUseOnly True if this data connection should be only used for unmetered 1961 * purposes only. 1962 * @return True if successful, otherwise false. 1963 */ 1964 private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) { 1965 if (DBG) log("setupData: apnContext=" + apnContext); 1966 apnContext.requestLog("setupData"); 1967 ApnSetting apnSetting; 1968 DcAsyncChannel dcac = null; 1969 1970 apnSetting = apnContext.getNextApnSetting(); 1971 1972 if (apnSetting == null) { 1973 if (DBG) log("setupData: return for no apn found!"); 1974 return false; 1975 } 1976 1977 int profileId = apnSetting.profileId; 1978 if (profileId == 0) { 1979 profileId = getApnProfileID(apnContext.getApnType()); 1980 } 1981 1982 // On CDMA, if we're explicitly asking for DUN, we need have 1983 // a dun-profiled connection so we can't share an existing one 1984 // On GSM/LTE we can share existing apn connections provided they support 1985 // this type. 1986 if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN || 1987 teardownForDun() == false) { 1988 dcac = checkForCompatibleConnectedApnContext(apnContext); 1989 if (dcac != null) { 1990 // Get the dcacApnSetting for the connection we want to share. 1991 ApnSetting dcacApnSetting = dcac.getApnSettingSync(); 1992 if (dcacApnSetting != null) { 1993 // Setting is good, so use it. 1994 apnSetting = dcacApnSetting; 1995 } 1996 } 1997 } 1998 if (dcac == null) { 1999 if (isOnlySingleDcAllowed(radioTech)) { 2000 if (isHigherPriorityApnContextActive(apnContext)) { 2001 if (DBG) { 2002 log("setupData: Higher priority ApnContext active. Ignoring call"); 2003 } 2004 return false; 2005 } 2006 2007 // Only lower priority calls left. Disconnect them all in this single PDP case 2008 // so that we can bring up the requested higher priority call (once we receive 2009 // response for deactivate request for the calls we are about to disconnect 2010 if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { 2011 // If any call actually requested to be disconnected, means we can't 2012 // bring up this connection yet as we need to wait for those data calls 2013 // to be disconnected. 2014 if (DBG) log("setupData: Some calls are disconnecting first. Wait and retry"); 2015 return false; 2016 } 2017 2018 // No other calls are active, so proceed 2019 if (DBG) log("setupData: Single pdp. Continue setting up data call."); 2020 } 2021 2022 dcac = findFreeDataConnection(); 2023 2024 if (dcac == null) { 2025 dcac = createDataConnection(); 2026 } 2027 2028 if (dcac == null) { 2029 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); 2030 return false; 2031 } 2032 } 2033 final int generation = apnContext.incAndGetConnectionGeneration(); 2034 if (DBG) { 2035 log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting + " gen#=" + generation); 2036 } 2037 2038 apnContext.setDataConnectionAc(dcac); 2039 apnContext.setApnSetting(apnSetting); 2040 apnContext.setState(DctConstants.State.CONNECTING); 2041 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 2042 2043 Message msg = obtainMessage(); 2044 msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; 2045 msg.obj = new Pair<ApnContext, Integer>(apnContext, generation); 2046 dcac.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation); 2047 2048 if (DBG) log("setupData: initing!"); 2049 return true; 2050 } 2051 2052 private void setInitialAttachApn() { 2053 ApnSetting iaApnSetting = null; 2054 ApnSetting defaultApnSetting = null; 2055 ApnSetting firstApnSetting = null; 2056 2057 log("setInitialApn: E mPreferredApn=" + mPreferredApn); 2058 2059 if (mPreferredApn != null && mPreferredApn.canHandleType(PhoneConstants.APN_TYPE_IA)) { 2060 iaApnSetting = mPreferredApn; 2061 } else if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { 2062 firstApnSetting = mAllApnSettings.get(0); 2063 log("setInitialApn: firstApnSetting=" + firstApnSetting); 2064 2065 // Search for Initial APN setting and the first apn that can handle default 2066 for (ApnSetting apn : mAllApnSettings) { 2067 if (apn.canHandleType(PhoneConstants.APN_TYPE_IA)) { 2068 // The Initial Attach APN is highest priority so use it if there is one 2069 log("setInitialApn: iaApnSetting=" + apn); 2070 iaApnSetting = apn; 2071 break; 2072 } else if ((defaultApnSetting == null) 2073 && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) { 2074 // Use the first default apn if no better choice 2075 log("setInitialApn: defaultApnSetting=" + apn); 2076 defaultApnSetting = apn; 2077 } 2078 } 2079 } 2080 2081 // The priority of apn candidates from highest to lowest is: 2082 // 1) APN_TYPE_IA (Initial Attach) 2083 // 2) mPreferredApn, i.e. the current preferred apn 2084 // 3) The first apn that than handle APN_TYPE_DEFAULT 2085 // 4) The first APN we can find. 2086 2087 ApnSetting initialAttachApnSetting = null; 2088 if (iaApnSetting != null) { 2089 if (DBG) log("setInitialAttachApn: using iaApnSetting"); 2090 initialAttachApnSetting = iaApnSetting; 2091 } else if (mPreferredApn != null) { 2092 if (DBG) log("setInitialAttachApn: using mPreferredApn"); 2093 initialAttachApnSetting = mPreferredApn; 2094 } else if (defaultApnSetting != null) { 2095 if (DBG) log("setInitialAttachApn: using defaultApnSetting"); 2096 initialAttachApnSetting = defaultApnSetting; 2097 } else if (firstApnSetting != null) { 2098 if (DBG) log("setInitialAttachApn: using firstApnSetting"); 2099 initialAttachApnSetting = firstApnSetting; 2100 } 2101 2102 if (initialAttachApnSetting == null) { 2103 if (DBG) log("setInitialAttachApn: X There in no available apn"); 2104 } else { 2105 if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting); 2106 2107 mPhone.mCi.setInitialAttachApn(new DataProfile(initialAttachApnSetting), 2108 mPhone.getServiceState().getDataRoamingFromRegistration(), null); 2109 } 2110 } 2111 2112 /** 2113 * Handles changes to the APN database. 2114 */ 2115 private void onApnChanged() { 2116 DctConstants.State overallState = getOverallState(); 2117 boolean isDisconnected = (overallState == DctConstants.State.IDLE || 2118 overallState == DctConstants.State.FAILED); 2119 2120 if (mPhone instanceof GsmCdmaPhone) { 2121 // The "current" may no longer be valid. MMS depends on this to send properly. TBD 2122 ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider(); 2123 } 2124 2125 // TODO: It'd be nice to only do this if the changed entrie(s) 2126 // match the current operator. 2127 if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); 2128 createAllApnList(); 2129 setInitialAttachApn(); 2130 cleanUpConnectionsOnUpdatedApns(!isDisconnected, Phone.REASON_APN_CHANGED); 2131 2132 // FIXME: See bug 17426028 maybe no conditional is needed. 2133 if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) { 2134 setupDataOnConnectableApns(Phone.REASON_APN_CHANGED); 2135 } 2136 } 2137 2138 /** 2139 * @param cid Connection id provided from RIL. 2140 * @return DataConnectionAc associated with specified cid. 2141 */ 2142 private DcAsyncChannel findDataConnectionAcByCid(int cid) { 2143 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 2144 if (dcac.getCidSync() == cid) { 2145 return dcac; 2146 } 2147 } 2148 return null; 2149 } 2150 2151 // TODO: For multiple Active APNs not exactly sure how to do this. 2152 private void gotoIdleAndNotifyDataConnection(String reason) { 2153 if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); 2154 notifyDataConnection(reason); 2155 } 2156 2157 /** 2158 * "Active" here means ApnContext isEnabled() and not in FAILED state 2159 * @param apnContext to compare with 2160 * @return true if higher priority active apn found 2161 */ 2162 private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { 2163 for (ApnContext otherContext : mPrioritySortedApnContexts) { 2164 if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; 2165 if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { 2166 return true; 2167 } 2168 } 2169 return false; 2170 } 2171 2172 /** 2173 * Reports if we support multiple connections or not. 2174 * This is a combination of factors, based on carrier and RAT. 2175 * @param rilRadioTech the RIL Radio Tech currently in use 2176 * @return true if only single DataConnection is allowed 2177 */ 2178 private boolean isOnlySingleDcAllowed(int rilRadioTech) { 2179 // Default single dc rats with no knowledge of carrier 2180 int[] singleDcRats = null; 2181 // get the carrier specific value, if it exists, from CarrierConfigManager. 2182 // generally configManager and bundle should not be null, but if they are it should be okay 2183 // to leave singleDcRats null as well 2184 CarrierConfigManager configManager = (CarrierConfigManager) 2185 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 2186 if (configManager != null) { 2187 PersistableBundle bundle = configManager.getConfig(); 2188 if (bundle != null) { 2189 singleDcRats = bundle.getIntArray( 2190 CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY); 2191 } 2192 } 2193 boolean onlySingleDcAllowed = false; 2194 if (Build.IS_DEBUGGABLE && 2195 SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { 2196 onlySingleDcAllowed = true; 2197 } 2198 if (singleDcRats != null) { 2199 for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) { 2200 if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true; 2201 } 2202 } 2203 2204 if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed); 2205 return onlySingleDcAllowed; 2206 } 2207 2208 void sendRestartRadio() { 2209 if (DBG)log("sendRestartRadio:"); 2210 Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO); 2211 sendMessage(msg); 2212 } 2213 2214 private void restartRadio() { 2215 if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); 2216 cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF); 2217 mPhone.getServiceStateTracker().powerOffRadioSafely(this); 2218 /* Note: no need to call setRadioPower(true). Assuming the desired 2219 * radio power state is still ON (as tracked by ServiceStateTracker), 2220 * ServiceStateTracker will call setRadioPower when it receives the 2221 * RADIO_STATE_CHANGED notification for the power off. And if the 2222 * desired power state has changed in the interim, we don't want to 2223 * override it with an unconditional power on. 2224 */ 2225 2226 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0")); 2227 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset + 1)); 2228 } 2229 2230 /** 2231 * Return true if data connection need to be setup after disconnected due to 2232 * reason. 2233 * 2234 * @param apnContext APN context 2235 * @return true if try setup data connection is need for this reason 2236 */ 2237 private boolean retryAfterDisconnected(ApnContext apnContext) { 2238 boolean retry = true; 2239 String reason = apnContext.getReason(); 2240 2241 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || 2242 (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) 2243 && isHigherPriorityApnContextActive(apnContext))) { 2244 retry = false; 2245 } 2246 return retry; 2247 } 2248 2249 private void startAlarmForReconnect(long delay, ApnContext apnContext) { 2250 String apnType = apnContext.getApnType(); 2251 2252 Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType); 2253 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); 2254 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType); 2255 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 2256 2257 // Get current sub id. 2258 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 2259 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 2260 2261 if (DBG) { 2262 log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction() 2263 + " apn=" + apnContext); 2264 } 2265 2266 PendingIntent alarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, 2267 intent, PendingIntent.FLAG_UPDATE_CURRENT); 2268 apnContext.setReconnectIntent(alarmIntent); 2269 2270 // Use the exact timer instead of the inexact one to provide better user experience. 2271 // In some extreme cases, we saw the retry was delayed for few minutes. 2272 // Note that if the stated trigger time is in the past, the alarm will be triggered 2273 // immediately. 2274 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 2275 SystemClock.elapsedRealtime() + delay, alarmIntent); 2276 } 2277 2278 private void notifyNoData(DcFailCause lastFailCauseCode, 2279 ApnContext apnContext) { 2280 if (DBG) log( "notifyNoData: type=" + apnContext.getApnType()); 2281 if (isPermanentFailure(lastFailCauseCode) 2282 && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) { 2283 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 2284 } 2285 } 2286 2287 public boolean getAutoAttachOnCreation() { 2288 return mAutoAttachOnCreation.get(); 2289 } 2290 2291 private void onRecordsLoadedOrSubIdChanged() { 2292 if (DBG) log("onRecordsLoadedOrSubIdChanged: createAllApnList"); 2293 mAutoAttachOnCreationConfig = mPhone.getContext().getResources() 2294 .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); 2295 2296 createAllApnList(); 2297 setInitialAttachApn(); 2298 if (mPhone.mCi.getRadioState().isOn()) { 2299 if (DBG) log("onRecordsLoadedOrSubIdChanged: notifying data availability"); 2300 notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); 2301 } 2302 setupDataOnConnectableApns(Phone.REASON_SIM_LOADED); 2303 } 2304 2305 /** 2306 * Action set from carrier signalling broadcast receivers to enable/disable metered apns. 2307 */ 2308 private void onSetCarrierDataEnabled(AsyncResult ar) { 2309 if (ar.exception != null) { 2310 Rlog.e(LOG_TAG, "CarrierDataEnable exception: " + ar.exception); 2311 return; 2312 } 2313 synchronized (mDataEnabledSettings) { 2314 boolean enabled = (boolean) ar.result; 2315 if (enabled != mDataEnabledSettings.isCarrierDataEnabled()) { 2316 if (DBG) { 2317 log("carrier Action: set metered apns enabled: " + enabled); 2318 } 2319 2320 // Disable/enable all metered apns 2321 mDataEnabledSettings.setCarrierDataEnabled(enabled); 2322 2323 if (!enabled) { 2324 // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users 2325 mPhone.notifyOtaspChanged(TelephonyManager.OTASP_SIM_UNPROVISIONED); 2326 // Tear down all metered apns 2327 cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); 2328 } else { 2329 // Re-evaluate Otasp state 2330 int otaspState = mPhone.getServiceStateTracker().getOtasp(); 2331 mPhone.notifyOtaspChanged(otaspState); 2332 2333 reevaluateDataConnections(); 2334 setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED); 2335 } 2336 } 2337 } 2338 } 2339 2340 private void onSimNotReady() { 2341 if (DBG) log("onSimNotReady"); 2342 2343 cleanUpAllConnections(true, Phone.REASON_SIM_NOT_READY); 2344 mAllApnSettings = null; 2345 mAutoAttachOnCreationConfig = false; 2346 // Clear auto attach as modem is expected to do a new attach once SIM is ready 2347 mAutoAttachOnCreation.set(false); 2348 } 2349 2350 private void onSetDependencyMet(String apnType, boolean met) { 2351 // don't allow users to tweak hipri to work around default dependency not met 2352 if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return; 2353 2354 ApnContext apnContext = mApnContexts.get(apnType); 2355 if (apnContext == null) { 2356 loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" + 2357 apnType + ", " + met + ")"); 2358 return; 2359 } 2360 applyNewState(apnContext, apnContext.isEnabled(), met); 2361 if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) { 2362 // tie actions on default to similar actions on HIPRI regarding dependencyMet 2363 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI); 2364 if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met); 2365 } 2366 } 2367 2368 public void setPolicyDataEnabled(boolean enabled) { 2369 if (DBG) log("setPolicyDataEnabled: " + enabled); 2370 Message msg = obtainMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE); 2371 msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED); 2372 sendMessage(msg); 2373 } 2374 2375 private void onSetPolicyDataEnabled(boolean enabled) { 2376 synchronized (mDataEnabledSettings) { 2377 final boolean prevEnabled = isDataEnabled(); 2378 if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) { 2379 mDataEnabledSettings.setPolicyDataEnabled(enabled); 2380 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and 2381 // handle the rest from there. 2382 if (prevEnabled != isDataEnabled()) { 2383 if (!prevEnabled) { 2384 reevaluateDataConnections(); 2385 onTrySetupData(Phone.REASON_DATA_ENABLED); 2386 } else { 2387 onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED); 2388 } 2389 } 2390 } 2391 } 2392 } 2393 2394 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) { 2395 boolean cleanup = false; 2396 boolean trySetup = false; 2397 String str ="applyNewState(" + apnContext.getApnType() + ", " + enabled + 2398 "(" + apnContext.isEnabled() + "), " + met + "(" + 2399 apnContext.getDependencyMet() +"))"; 2400 if (DBG) log(str); 2401 apnContext.requestLog(str); 2402 2403 if (apnContext.isReady()) { 2404 cleanup = true; 2405 if (enabled && met) { 2406 DctConstants.State state = apnContext.getState(); 2407 switch(state) { 2408 case CONNECTING: 2409 case CONNECTED: 2410 case DISCONNECTING: 2411 // We're "READY" and active so just return 2412 if (DBG) log("applyNewState: 'ready' so return"); 2413 apnContext.requestLog("applyNewState state=" + state + ", so return"); 2414 return; 2415 case IDLE: 2416 // fall through: this is unexpected but if it happens cleanup and try setup 2417 case FAILED: 2418 case SCANNING: 2419 case RETRYING: { 2420 // We're "READY" but not active so disconnect (cleanup = true) and 2421 // connect (trySetup = true) to be sure we retry the connection. 2422 trySetup = true; 2423 apnContext.setReason(Phone.REASON_DATA_ENABLED); 2424 break; 2425 } 2426 } 2427 } else if (met) { 2428 apnContext.setReason(Phone.REASON_DATA_DISABLED); 2429 // If ConnectivityService has disabled this network, stop trying to bring 2430 // it up, but do not tear it down - ConnectivityService will do that 2431 // directly by talking with the DataConnection. 2432 // 2433 // This doesn't apply to DUN, however. Those connections have special 2434 // requirements from carriers and we need stop using them when the dun 2435 // request goes away. This applies to both CDMA and GSM because they both 2436 // can declare the DUN APN sharable by default traffic, thus still satisfying 2437 // those requests and not torn down organically. 2438 if ((apnContext.getApnType() == PhoneConstants.APN_TYPE_DUN && teardownForDun()) 2439 || apnContext.getState() != DctConstants.State.CONNECTED) { 2440 str = "Clean up the connection. Apn type = " + apnContext.getApnType() 2441 + ", state = " + apnContext.getState(); 2442 if (DBG) log(str); 2443 apnContext.requestLog(str); 2444 cleanup = true; 2445 } else { 2446 cleanup = false; 2447 } 2448 } else { 2449 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); 2450 } 2451 } else { 2452 if (enabled && met) { 2453 if (apnContext.isEnabled()) { 2454 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); 2455 } else { 2456 apnContext.setReason(Phone.REASON_DATA_ENABLED); 2457 } 2458 if (apnContext.getState() == DctConstants.State.FAILED) { 2459 apnContext.setState(DctConstants.State.IDLE); 2460 } 2461 trySetup = true; 2462 } 2463 } 2464 apnContext.setEnabled(enabled); 2465 apnContext.setDependencyMet(met); 2466 if (cleanup) cleanUpConnection(true, apnContext); 2467 if (trySetup) { 2468 apnContext.resetErrorCodeRetries(); 2469 trySetupData(apnContext); 2470 } 2471 } 2472 2473 private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) { 2474 String apnType = apnContext.getApnType(); 2475 ApnSetting dunSetting = null; 2476 2477 if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) { 2478 dunSetting = fetchDunApn(); 2479 } 2480 if (DBG) { 2481 log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext ); 2482 } 2483 2484 DcAsyncChannel potentialDcac = null; 2485 ApnContext potentialApnCtx = null; 2486 for (ApnContext curApnCtx : mApnContexts.values()) { 2487 DcAsyncChannel curDcac = curApnCtx.getDcAc(); 2488 if (curDcac != null) { 2489 ApnSetting apnSetting = curApnCtx.getApnSetting(); 2490 log("apnSetting: " + apnSetting); 2491 if (dunSetting != null) { 2492 if (dunSetting.equals(apnSetting)) { 2493 switch (curApnCtx.getState()) { 2494 case CONNECTED: 2495 if (DBG) { 2496 log("checkForCompatibleConnectedApnContext:" 2497 + " found dun conn=" + curDcac 2498 + " curApnCtx=" + curApnCtx); 2499 } 2500 return curDcac; 2501 case RETRYING: 2502 case CONNECTING: 2503 potentialDcac = curDcac; 2504 potentialApnCtx = curApnCtx; 2505 default: 2506 // Not connected, potential unchanged 2507 break; 2508 } 2509 } 2510 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) { 2511 switch (curApnCtx.getState()) { 2512 case CONNECTED: 2513 if (DBG) { 2514 log("checkForCompatibleConnectedApnContext:" 2515 + " found canHandle conn=" + curDcac 2516 + " curApnCtx=" + curApnCtx); 2517 } 2518 return curDcac; 2519 case RETRYING: 2520 case CONNECTING: 2521 potentialDcac = curDcac; 2522 potentialApnCtx = curApnCtx; 2523 default: 2524 // Not connected, potential unchanged 2525 break; 2526 } 2527 } 2528 } else { 2529 if (VDBG) { 2530 log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx); 2531 } 2532 } 2533 } 2534 if (potentialDcac != null) { 2535 if (DBG) { 2536 log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac 2537 + " curApnCtx=" + potentialApnCtx); 2538 } 2539 return potentialDcac; 2540 } 2541 2542 if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext); 2543 return null; 2544 } 2545 2546 public void setEnabled(int id, boolean enable) { 2547 Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN); 2548 msg.arg1 = id; 2549 msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 2550 sendMessage(msg); 2551 } 2552 2553 private void onEnableApn(int apnId, int enabled) { 2554 ApnContext apnContext = mApnContextsById.get(apnId); 2555 if (apnContext == null) { 2556 loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext"); 2557 return; 2558 } 2559 // TODO change our retry manager to use the appropriate numbers for the new APN 2560 if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState"); 2561 applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet()); 2562 2563 if ((enabled == DctConstants.DISABLED) && 2564 isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) && 2565 !isHigherPriorityApnContextActive(apnContext)) { 2566 2567 if(DBG) log("onEnableApn: isOnlySingleDcAllowed true & higher priority APN disabled"); 2568 // If the highest priority APN is disabled and only single 2569 // data call is allowed, try to setup data call on other connectable APN. 2570 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION); 2571 } 2572 } 2573 2574 // TODO: We shouldnt need this. 2575 private boolean onTrySetupData(String reason) { 2576 if (DBG) log("onTrySetupData: reason=" + reason); 2577 setupDataOnConnectableApns(reason); 2578 return true; 2579 } 2580 2581 private boolean onTrySetupData(ApnContext apnContext) { 2582 if (DBG) log("onTrySetupData: apnContext=" + apnContext); 2583 return trySetupData(apnContext); 2584 } 2585 2586 /** 2587 * Return current {@link android.provider.Settings.Global#MOBILE_DATA} value. 2588 */ 2589 //TODO: Merge this into DataSettings. And probably should rename to getUserDataEnabled(). 2590 public boolean getDataEnabled() { 2591 final int device_provisioned = 2592 Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0); 2593 2594 boolean retVal = "true".equalsIgnoreCase(SystemProperties.get( 2595 "ro.com.android.mobiledata", "true")); 2596 if (TelephonyManager.getDefault().getSimCount() == 1) { 2597 retVal = Settings.Global.getInt(mResolver, Settings.Global.MOBILE_DATA, 2598 retVal ? 1 : 0) != 0; 2599 } else { 2600 int phoneSubId = mPhone.getSubId(); 2601 try { 2602 retVal = TelephonyManager.getIntWithSubId(mResolver, 2603 Settings.Global.MOBILE_DATA, phoneSubId) != 0; 2604 } catch (SettingNotFoundException e) { 2605 // use existing retVal 2606 } 2607 } 2608 if (VDBG) log("getDataEnabled: retVal=" + retVal); 2609 if (device_provisioned == 0) { 2610 // device is still getting provisioned - use whatever setting they 2611 // want during this process 2612 // 2613 // use the normal data_enabled setting (retVal, determined above) 2614 // as the default if nothing else is set 2615 final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata", 2616 retVal ? "true" : "false"); 2617 retVal = "true".equalsIgnoreCase(prov_property); 2618 2619 final int prov_mobile_data = Settings.Global.getInt(mResolver, 2620 Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 2621 retVal ? 1 : 0); 2622 retVal = prov_mobile_data != 0; 2623 log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property + 2624 ", " + prov_mobile_data + ")"); 2625 } 2626 2627 return retVal; 2628 } 2629 2630 /** 2631 * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only 2632 */ 2633 public void setDataRoamingEnabledByUser(boolean enabled) { 2634 final int phoneSubId = mPhone.getSubId(); 2635 if (getDataRoamingEnabled() != enabled) { 2636 int roaming = enabled ? 1 : 0; 2637 2638 // For single SIM phones, this is a per phone property. 2639 if (TelephonyManager.getDefault().getSimCount() == 1) { 2640 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING, roaming); 2641 setDataRoamingFromUserAction(true); 2642 } else { 2643 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING + 2644 phoneSubId, roaming); 2645 } 2646 2647 mSubscriptionManager.setDataRoaming(roaming, phoneSubId); 2648 // will trigger handleDataOnRoamingChange() through observer 2649 if (DBG) { 2650 log("setDataRoamingEnabledByUser: set phoneSubId=" + phoneSubId 2651 + " isRoaming=" + enabled); 2652 } 2653 } else { 2654 if (DBG) { 2655 log("setDataRoamingEnabledByUser: unchanged phoneSubId=" + phoneSubId 2656 + " isRoaming=" + enabled); 2657 } 2658 } 2659 } 2660 2661 /** 2662 * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. 2663 */ 2664 public boolean getDataRoamingEnabled() { 2665 boolean isDataRoamingEnabled; 2666 final int phoneSubId = mPhone.getSubId(); 2667 2668 try { 2669 // For single SIM phones, this is a per phone property. 2670 if (TelephonyManager.getDefault().getSimCount() == 1) { 2671 isDataRoamingEnabled = Settings.Global.getInt(mResolver, 2672 Settings.Global.DATA_ROAMING, getDefaultDataRoamingEnabled() ? 1 : 0) != 0; 2673 } else { 2674 isDataRoamingEnabled = TelephonyManager.getIntWithSubId(mResolver, 2675 Settings.Global.DATA_ROAMING, phoneSubId) != 0; 2676 } 2677 } catch (SettingNotFoundException snfe) { 2678 if (DBG) log("getDataRoamingEnabled: SettingNofFoundException snfe=" + snfe); 2679 isDataRoamingEnabled = getDefaultDataRoamingEnabled(); 2680 } 2681 if (VDBG) { 2682 log("getDataRoamingEnabled: phoneSubId=" + phoneSubId 2683 + " isDataRoamingEnabled=" + isDataRoamingEnabled); 2684 } 2685 return isDataRoamingEnabled; 2686 } 2687 2688 /** 2689 * get default values for {@link Settings.Global#DATA_ROAMING} 2690 * return {@code true} if either 2691 * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or 2692 * system property ro.com.android.dataroaming is set to true. otherwise return {@code false} 2693 */ 2694 private boolean getDefaultDataRoamingEnabled() { 2695 final CarrierConfigManager configMgr = (CarrierConfigManager) 2696 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 2697 boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get( 2698 "ro.com.android.dataroaming", "false")); 2699 isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean( 2700 CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL); 2701 return isDataRoamingEnabled; 2702 } 2703 2704 /** 2705 * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING} 2706 * if the setting is not from user actions. default value is based on carrier config and system 2707 * properties. 2708 */ 2709 private void setDefaultDataRoamingEnabled() { 2710 // For single SIM phones, this is a per phone property. 2711 String setting = Settings.Global.DATA_ROAMING; 2712 boolean useCarrierSpecificDefault = false; 2713 if (TelephonyManager.getDefault().getSimCount() != 1) { 2714 setting = setting + mPhone.getSubId(); 2715 try { 2716 Settings.Global.getInt(mResolver, setting); 2717 } catch (SettingNotFoundException ex) { 2718 // For msim, update to carrier default if uninitialized. 2719 useCarrierSpecificDefault = true; 2720 } 2721 } else if (!isDataRoamingFromUserAction()) { 2722 // for single sim device, update to carrier default if user action is not set 2723 useCarrierSpecificDefault = true; 2724 } 2725 if (useCarrierSpecificDefault) { 2726 boolean defaultVal = getDefaultDataRoamingEnabled(); 2727 log("setDefaultDataRoamingEnabled: " + setting + "default value: " + defaultVal); 2728 Settings.Global.putInt(mResolver, setting, defaultVal ? 1 : 0); 2729 mSubscriptionManager.setDataRoaming(defaultVal ? 1 : 0, mPhone.getSubId()); 2730 } 2731 } 2732 2733 private boolean isDataRoamingFromUserAction() { 2734 final SharedPreferences sp = PreferenceManager 2735 .getDefaultSharedPreferences(mPhone.getContext()); 2736 // since we don't want to unset user preference from system update, pass true as the default 2737 // value if shared pref does not exist and set shared pref to false explicitly from factory 2738 // reset. 2739 if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY) 2740 && Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) { 2741 sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); 2742 } 2743 return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); 2744 } 2745 2746 private void setDataRoamingFromUserAction(boolean isUserAction) { 2747 final SharedPreferences.Editor sp = PreferenceManager 2748 .getDefaultSharedPreferences(mPhone.getContext()).edit(); 2749 sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit(); 2750 } 2751 2752 // When the data roaming status changes from roaming to non-roaming. 2753 private void onDataRoamingOff() { 2754 if (DBG) log("onDataRoamingOff"); 2755 2756 if (!getDataRoamingEnabled()) { 2757 // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn 2758 // attach and send the data profile again as the modem should have both roaming and 2759 // non-roaming protocol in place. Modem should choose the right protocol based on the 2760 // roaming condition. 2761 setInitialAttachApn(); 2762 setDataProfilesAsNeeded(); 2763 2764 // If the user did not enable data roaming, now when we transit from roaming to 2765 // non-roaming, we should try to reestablish the data connection. 2766 2767 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF); 2768 setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF); 2769 } else { 2770 notifyDataConnection(Phone.REASON_ROAMING_OFF); 2771 } 2772 } 2773 2774 // This method is called 2775 // 1. When the data roaming status changes from non-roaming to roaming. 2776 // 2. When allowed data roaming settings is changed by the user. 2777 private void onDataRoamingOnOrSettingsChanged() { 2778 if (DBG) log("onDataRoamingOnOrSettingsChanged"); 2779 2780 // Check if the device is actually data roaming 2781 if (!mPhone.getServiceState().getDataRoaming()) { 2782 if (DBG) log("device is not roaming. ignored the request."); 2783 return; 2784 } 2785 2786 if (getDataRoamingEnabled()) { 2787 if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); 2788 2789 setupDataOnConnectableApns(Phone.REASON_ROAMING_ON); 2790 notifyDataConnection(Phone.REASON_ROAMING_ON); 2791 } else { 2792 // If the user does not turn on data roaming, when we transit from non-roaming to 2793 // roaming, we need to tear down the data connection otherwise the user might be 2794 // charged for data roaming usage. 2795 if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming."); 2796 cleanUpAllConnections(true, Phone.REASON_ROAMING_ON); 2797 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON); 2798 } 2799 } 2800 2801 private void onRadioAvailable() { 2802 if (DBG) log("onRadioAvailable"); 2803 if (mPhone.getSimulatedRadioControl() != null) { 2804 // Assume data is connected on the simulator 2805 // FIXME this can be improved 2806 // setState(DctConstants.State.CONNECTED); 2807 notifyDataConnection(null); 2808 2809 log("onRadioAvailable: We're on the simulator; assuming data is connected"); 2810 } 2811 2812 IccRecords r = mIccRecords.get(); 2813 if (r != null && r.getRecordsLoaded()) { 2814 notifyOffApnsOfAvailability(null); 2815 } 2816 2817 if (getOverallState() != DctConstants.State.IDLE) { 2818 cleanUpConnection(true, null); 2819 } 2820 } 2821 2822 private void onRadioOffOrNotAvailable() { 2823 // Make sure our reconnect delay starts at the initial value 2824 // next time the radio comes on 2825 2826 mReregisterOnReconnectFailure = false; 2827 2828 // Clear auto attach as modem is expected to do a new attach 2829 mAutoAttachOnCreation.set(false); 2830 2831 if (mPhone.getSimulatedRadioControl() != null) { 2832 // Assume data is connected on the simulator 2833 // FIXME this can be improved 2834 log("We're on the simulator; assuming radio off is meaningless"); 2835 } else { 2836 if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); 2837 cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF); 2838 } 2839 notifyOffApnsOfAvailability(null); 2840 } 2841 2842 private void completeConnection(ApnContext apnContext) { 2843 2844 if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext); 2845 2846 if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) { 2847 if (DBG) { 2848 log("completeConnection: MOBILE_PROVISIONING_ACTION url=" 2849 + mProvisioningUrl); 2850 } 2851 Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, 2852 Intent.CATEGORY_APP_BROWSER); 2853 newIntent.setData(Uri.parse(mProvisioningUrl)); 2854 newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | 2855 Intent.FLAG_ACTIVITY_NEW_TASK); 2856 try { 2857 mPhone.getContext().startActivity(newIntent); 2858 } catch (ActivityNotFoundException e) { 2859 loge("completeConnection: startActivityAsUser failed" + e); 2860 } 2861 } 2862 mIsProvisioning = false; 2863 mProvisioningUrl = null; 2864 if (mProvisioningSpinner != null) { 2865 sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, 2866 mProvisioningSpinner)); 2867 } 2868 2869 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 2870 startNetStatPoll(); 2871 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 2872 } 2873 2874 /** 2875 * A SETUP (aka bringUp) has completed, possibly with an error. If 2876 * there is an error this method will call {@link #onDataSetupCompleteError}. 2877 */ 2878 private void onDataSetupComplete(AsyncResult ar) { 2879 2880 DcFailCause cause = DcFailCause.UNKNOWN; 2881 boolean handleError = false; 2882 ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete"); 2883 2884 if (apnContext == null) return; 2885 2886 if (ar.exception == null) { 2887 DcAsyncChannel dcac = apnContext.getDcAc(); 2888 2889 if (RADIO_TESTS) { 2890 // Note: To change radio.test.onDSC.null.dcac from command line you need to 2891 // adb root and adb remount and from the command line you can only change the 2892 // value to 1 once. To change it a second time you can reboot or execute 2893 // adb shell stop and then adb shell start. The command line to set the value is: 2894 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');" 2895 ContentResolver cr = mPhone.getContext().getContentResolver(); 2896 String radioTestProperty = "radio.test.onDSC.null.dcac"; 2897 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) { 2898 log("onDataSetupComplete: " + radioTestProperty + 2899 " is true, set dcac to null and reset property to false"); 2900 dcac = null; 2901 Settings.System.putInt(cr, radioTestProperty, 0); 2902 log("onDataSetupComplete: " + radioTestProperty + "=" + 2903 Settings.System.getInt(mPhone.getContext().getContentResolver(), 2904 radioTestProperty, -1)); 2905 } 2906 } 2907 if (dcac == null) { 2908 log("onDataSetupComplete: no connection to DC, handle as error"); 2909 cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN; 2910 handleError = true; 2911 } else { 2912 ApnSetting apn = apnContext.getApnSetting(); 2913 if (DBG) { 2914 log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn)); 2915 } 2916 if (apn != null && apn.proxy != null && apn.proxy.length() != 0) { 2917 try { 2918 String port = apn.port; 2919 if (TextUtils.isEmpty(port)) port = "8080"; 2920 ProxyInfo proxy = new ProxyInfo(apn.proxy, 2921 Integer.parseInt(port), null); 2922 dcac.setLinkPropertiesHttpProxySync(proxy); 2923 } catch (NumberFormatException e) { 2924 loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" + 2925 apn.port + "): " + e); 2926 } 2927 } 2928 2929 // everything is setup 2930 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) { 2931 try { 2932 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true"); 2933 } catch (RuntimeException ex) { 2934 log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to true"); 2935 } 2936 if (mCanSetPreferApn && mPreferredApn == null) { 2937 if (DBG) log("onDataSetupComplete: PREFERRED APN is null"); 2938 mPreferredApn = apn; 2939 if (mPreferredApn != null) { 2940 setPreferredApn(mPreferredApn.id); 2941 } 2942 } 2943 } else { 2944 try { 2945 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false"); 2946 } catch (RuntimeException ex) { 2947 log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false"); 2948 } 2949 } 2950 2951 // A connection is setup 2952 apnContext.setState(DctConstants.State.CONNECTED); 2953 2954 boolean isProvApn = apnContext.isProvisioningApn(); 2955 final ConnectivityManager cm = ConnectivityManager.from(mPhone.getContext()); 2956 if (mProvisionBroadcastReceiver != null) { 2957 mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); 2958 mProvisionBroadcastReceiver = null; 2959 } 2960 if ((!isProvApn) || mIsProvisioning) { 2961 // Hide any provisioning notification. 2962 cm.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_MOBILE, 2963 mProvisionActionName); 2964 // Complete the connection normally notifying the world we're connected. 2965 // We do this if this isn't a special provisioning apn or if we've been 2966 // told its time to provision. 2967 completeConnection(apnContext); 2968 } else { 2969 // This is a provisioning APN that we're reporting as connected. Later 2970 // when the user desires to upgrade this to a "default" connection, 2971 // mIsProvisioning == true, we'll go through the code path above. 2972 // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING 2973 // is sent to the DCT. 2974 if (DBG) { 2975 log("onDataSetupComplete: successful, BUT send connected to prov apn as" 2976 + " mIsProvisioning:" + mIsProvisioning + " == false" 2977 + " && (isProvisioningApn:" + isProvApn + " == true"); 2978 } 2979 2980 // While radio is up, grab provisioning URL. The URL contains ICCID which 2981 // disappears when radio is off. 2982 mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver( 2983 cm.getMobileProvisioningUrl(), 2984 TelephonyManager.getDefault().getNetworkOperatorName()); 2985 mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver, 2986 new IntentFilter(mProvisionActionName)); 2987 // Put up user notification that sign-in is required. 2988 cm.setProvisioningNotificationVisible(true, ConnectivityManager.TYPE_MOBILE, 2989 mProvisionActionName); 2990 // Turn off radio to save battery and avoid wasting carrier resources. 2991 // The network isn't usable and network validation will just fail anyhow. 2992 setRadio(false); 2993 } 2994 if (DBG) { 2995 log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType() 2996 + ", reason:" + apnContext.getReason()); 2997 } 2998 if (Build.IS_DEBUGGABLE) { 2999 // adb shell setprop persist.radio.test.pco [pco_val] 3000 String radioTestProperty = "persist.radio.test.pco"; 3001 int pcoVal = SystemProperties.getInt(radioTestProperty, -1); 3002 if (pcoVal != -1) { 3003 log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal); 3004 final byte[] value = new byte[1]; 3005 value[0] = (byte) pcoVal; 3006 final Intent intent = 3007 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE); 3008 intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, "default"); 3009 intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, "IPV4V6"); 3010 intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, 0xFF00); 3011 intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, value); 3012 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); 3013 } 3014 } 3015 } 3016 } else { 3017 cause = (DcFailCause) (ar.result); 3018 if (DBG) { 3019 ApnSetting apn = apnContext.getApnSetting(); 3020 log(String.format("onDataSetupComplete: error apn=%s cause=%s", 3021 (apn == null ? "unknown" : apn.apn), cause)); 3022 } 3023 if (cause.isEventLoggable()) { 3024 // Log this failure to the Event Logs. 3025 int cid = getCellLocationId(); 3026 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, 3027 cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType()); 3028 } 3029 ApnSetting apn = apnContext.getApnSetting(); 3030 mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(), 3031 apnContext.getApnType(), apn != null ? apn.apn : "unknown", cause.toString()); 3032 3033 // Compose broadcast intent send to the specific carrier signaling receivers 3034 Intent intent = new Intent(TelephonyIntents 3035 .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED); 3036 intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause.getErrorCode()); 3037 intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType()); 3038 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); 3039 3040 if (cause.isRestartRadioFail(mPhone.getContext(), mPhone.getSubId()) || 3041 apnContext.restartOnError(cause.getErrorCode())) { 3042 if (DBG) log("Modem restarted."); 3043 sendRestartRadio(); 3044 } 3045 3046 // If the data call failure cause is a permanent failure, we mark the APN as permanent 3047 // failed. 3048 if (isPermanentFailure(cause)) { 3049 log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn); 3050 apnContext.markApnPermanentFailed(apn); 3051 } 3052 3053 handleError = true; 3054 } 3055 3056 if (handleError) { 3057 onDataSetupCompleteError(ar); 3058 } 3059 3060 /* If flag is set to false after SETUP_DATA_CALL is invoked, we need 3061 * to clean data connections. 3062 */ 3063 if (!mDataEnabledSettings.isInternalDataEnabled()) { 3064 cleanUpAllConnections(Phone.REASON_DATA_DISABLED); 3065 } 3066 3067 } 3068 3069 /** 3070 * check for obsolete messages. Return ApnContext if valid, null if not 3071 */ 3072 private ApnContext getValidApnContext(AsyncResult ar, String logString) { 3073 if (ar != null && ar.userObj instanceof Pair) { 3074 Pair<ApnContext, Integer>pair = (Pair<ApnContext, Integer>)ar.userObj; 3075 ApnContext apnContext = pair.first; 3076 if (apnContext != null) { 3077 final int generation = apnContext.getConnectionGeneration(); 3078 if (DBG) { 3079 log("getValidApnContext (" + logString + ") on " + apnContext + " got " + 3080 generation + " vs " + pair.second); 3081 } 3082 if (generation == pair.second) { 3083 return apnContext; 3084 } else { 3085 log("ignoring obsolete " + logString); 3086 return null; 3087 } 3088 } 3089 } 3090 throw new RuntimeException(logString + ": No apnContext"); 3091 } 3092 3093 /** 3094 * Error has occurred during the SETUP {aka bringUP} request and the DCT 3095 * should either try the next waiting APN or start over from the 3096 * beginning if the list is empty. Between each SETUP request there will 3097 * be a delay defined by {@link #getApnDelay()}. 3098 */ 3099 private void onDataSetupCompleteError(AsyncResult ar) { 3100 3101 ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError"); 3102 3103 if (apnContext == null) return; 3104 3105 long delay = apnContext.getDelayForNextApn(mFailFast); 3106 3107 // Check if we need to retry or not. 3108 if (delay >= 0) { 3109 if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay); 3110 apnContext.setState(DctConstants.State.SCANNING); 3111 // Wait a bit before trying the next APN, so that 3112 // we're not tying up the RIL command channel 3113 startAlarmForReconnect(delay, apnContext); 3114 } else { 3115 // If we are not going to retry any APN, set this APN context to failed state. 3116 // This would be the final state of a data connection. 3117 apnContext.setState(DctConstants.State.FAILED); 3118 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType()); 3119 apnContext.setDataConnectionAc(null); 3120 log("onDataSetupCompleteError: Stop retrying APNs."); 3121 } 3122 } 3123 3124 /** 3125 * Called when EVENT_REDIRECTION_DETECTED is received. 3126 */ 3127 private void onDataConnectionRedirected(String redirectUrl) { 3128 if (!TextUtils.isEmpty(redirectUrl)) { 3129 Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED); 3130 intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl); 3131 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); 3132 log("Notify carrier signal receivers with redirectUrl: " + redirectUrl); 3133 } 3134 } 3135 3136 /** 3137 * Called when EVENT_DISCONNECT_DONE is received. 3138 */ 3139 private void onDisconnectDone(AsyncResult ar) { 3140 ApnContext apnContext = getValidApnContext(ar, "onDisconnectDone"); 3141 if (apnContext == null) return; 3142 3143 if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext); 3144 apnContext.setState(DctConstants.State.IDLE); 3145 3146 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 3147 3148 // if all data connection are gone, check whether Airplane mode request was 3149 // pending. 3150 if (isDisconnected()) { 3151 if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { 3152 if (DBG) log("onDisconnectDone: radio will be turned off, no retries"); 3153 // Radio will be turned off. No need to retry data setup 3154 apnContext.setApnSetting(null); 3155 apnContext.setDataConnectionAc(null); 3156 3157 // Need to notify disconnect as well, in the case of switching Airplane mode. 3158 // Otherwise, it would cause 30s delayed to turn on Airplane mode. 3159 if (mDisconnectPendingCount > 0) { 3160 mDisconnectPendingCount--; 3161 } 3162 3163 if (mDisconnectPendingCount == 0) { 3164 notifyDataDisconnectComplete(); 3165 notifyAllDataDisconnected(); 3166 } 3167 return; 3168 } 3169 } 3170 // If APN is still enabled, try to bring it back up automatically 3171 if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) { 3172 try { 3173 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false"); 3174 } catch (RuntimeException ex) { 3175 log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false"); 3176 } 3177 // Wait a bit before trying the next APN, so that 3178 // we're not tying up the RIL command channel. 3179 // This also helps in any external dependency to turn off the context. 3180 if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect"); 3181 long delay = apnContext.getRetryAfterDisconnectDelay(); 3182 if (delay > 0) { 3183 // Data connection is in IDLE state, so when we reconnect later, we'll rebuild 3184 // the waiting APN list, which will also reset/reconfigure the retry manager. 3185 startAlarmForReconnect(delay, apnContext); 3186 } 3187 } else { 3188 boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean( 3189 com.android.internal.R.bool.config_restartRadioAfterProvisioning); 3190 3191 if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) { 3192 log("onDisconnectDone: restartRadio after provisioning"); 3193 restartRadio(); 3194 } 3195 apnContext.setApnSetting(null); 3196 apnContext.setDataConnectionAc(null); 3197 if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) { 3198 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn"); 3199 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION); 3200 } else { 3201 if(DBG) log("onDisconnectDone: not retrying"); 3202 } 3203 } 3204 3205 if (mDisconnectPendingCount > 0) 3206 mDisconnectPendingCount--; 3207 3208 if (mDisconnectPendingCount == 0) { 3209 apnContext.setConcurrentVoiceAndDataAllowed( 3210 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()); 3211 notifyDataDisconnectComplete(); 3212 notifyAllDataDisconnected(); 3213 } 3214 3215 } 3216 3217 /** 3218 * Called when EVENT_DISCONNECT_DC_RETRYING is received. 3219 */ 3220 private void onDisconnectDcRetrying(AsyncResult ar) { 3221 // We could just do this in DC!!! 3222 ApnContext apnContext = getValidApnContext(ar, "onDisconnectDcRetrying"); 3223 if (apnContext == null) return; 3224 3225 apnContext.setState(DctConstants.State.RETRYING); 3226 if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext); 3227 3228 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 3229 } 3230 3231 private void onVoiceCallStarted() { 3232 if (DBG) log("onVoiceCallStarted"); 3233 mInVoiceCall = true; 3234 if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 3235 if (DBG) log("onVoiceCallStarted stop polling"); 3236 stopNetStatPoll(); 3237 stopDataStallAlarm(); 3238 notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); 3239 } 3240 } 3241 3242 private void onVoiceCallEnded() { 3243 if (DBG) log("onVoiceCallEnded"); 3244 mInVoiceCall = false; 3245 if (isConnected()) { 3246 if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 3247 startNetStatPoll(); 3248 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 3249 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); 3250 } else { 3251 // clean slate after call end. 3252 resetPollStats(); 3253 } 3254 } 3255 // reset reconnect timer 3256 setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED); 3257 } 3258 3259 private void onCleanUpConnection(boolean tearDown, int apnId, String reason) { 3260 if (DBG) log("onCleanUpConnection"); 3261 ApnContext apnContext = mApnContextsById.get(apnId); 3262 if (apnContext != null) { 3263 apnContext.setReason(reason); 3264 cleanUpConnection(tearDown, apnContext); 3265 } 3266 } 3267 3268 private boolean isConnected() { 3269 for (ApnContext apnContext : mApnContexts.values()) { 3270 if (apnContext.getState() == DctConstants.State.CONNECTED) { 3271 // At least one context is connected, return true 3272 return true; 3273 } 3274 } 3275 // There are not any contexts connected, return false 3276 return false; 3277 } 3278 3279 public boolean isDisconnected() { 3280 for (ApnContext apnContext : mApnContexts.values()) { 3281 if (!apnContext.isDisconnected()) { 3282 // At least one context was not disconnected return false 3283 return false; 3284 } 3285 } 3286 // All contexts were disconnected so return true 3287 return true; 3288 } 3289 3290 private void notifyDataConnection(String reason) { 3291 if (DBG) log("notifyDataConnection: reason=" + reason); 3292 for (ApnContext apnContext : mApnContexts.values()) { 3293 if (mAttached.get() && apnContext.isReady()) { 3294 if (DBG) log("notifyDataConnection: type:" + apnContext.getApnType()); 3295 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 3296 apnContext.getApnType()); 3297 } 3298 } 3299 notifyOffApnsOfAvailability(reason); 3300 } 3301 3302 private void setDataProfilesAsNeeded() { 3303 if (DBG) log("setDataProfilesAsNeeded"); 3304 if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { 3305 ArrayList<DataProfile> dps = new ArrayList<DataProfile>(); 3306 for (ApnSetting apn : mAllApnSettings) { 3307 if (apn.modemCognitive) { 3308 DataProfile dp = new DataProfile(apn); 3309 if (!dps.contains(dp)) { 3310 dps.add(dp); 3311 } 3312 } 3313 } 3314 if (dps.size() > 0) { 3315 mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), 3316 mPhone.getServiceState().getDataRoamingFromRegistration(), null); 3317 } 3318 } 3319 } 3320 3321 /** 3322 * Based on the sim operator numeric, create a list for all possible 3323 * Data Connections and setup the preferredApn. 3324 */ 3325 private void createAllApnList() { 3326 mMvnoMatched = false; 3327 mAllApnSettings = new ArrayList<>(); 3328 IccRecords r = mIccRecords.get(); 3329 String operator = (r != null) ? r.getOperatorNumeric() : ""; 3330 if (operator != null) { 3331 String selection = Telephony.Carriers.NUMERIC + " = '" + operator + "'"; 3332 // query only enabled apn. 3333 // carrier_enabled : 1 means enabled apn, 0 disabled apn. 3334 // selection += " and carrier_enabled = 1"; 3335 if (DBG) log("createAllApnList: selection=" + selection); 3336 3337 // ORDER BY Telephony.Carriers._ID ("_id") 3338 Cursor cursor = mPhone.getContext().getContentResolver().query( 3339 Telephony.Carriers.CONTENT_URI, null, selection, null, Telephony.Carriers._ID); 3340 3341 if (cursor != null) { 3342 if (cursor.getCount() > 0) { 3343 mAllApnSettings = createApnList(cursor); 3344 } 3345 cursor.close(); 3346 } 3347 } 3348 3349 addEmergencyApnSetting(); 3350 3351 dedupeApnSettings(); 3352 3353 if (mAllApnSettings.isEmpty()) { 3354 if (DBG) log("createAllApnList: No APN found for carrier: " + operator); 3355 mPreferredApn = null; 3356 // TODO: What is the right behavior? 3357 //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN); 3358 } else { 3359 mPreferredApn = getPreferredApn(); 3360 if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { 3361 mPreferredApn = null; 3362 setPreferredApn(-1); 3363 } 3364 if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); 3365 } 3366 if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); 3367 3368 setDataProfilesAsNeeded(); 3369 } 3370 3371 private void dedupeApnSettings() { 3372 ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>(); 3373 3374 // coalesce APNs if they are similar enough to prevent 3375 // us from bringing up two data calls with the same interface 3376 int i = 0; 3377 while (i < mAllApnSettings.size() - 1) { 3378 ApnSetting first = mAllApnSettings.get(i); 3379 ApnSetting second = null; 3380 int j = i + 1; 3381 while (j < mAllApnSettings.size()) { 3382 second = mAllApnSettings.get(j); 3383 if (first.similar(second)) { 3384 ApnSetting newApn = mergeApns(first, second); 3385 mAllApnSettings.set(i, newApn); 3386 first = newApn; 3387 mAllApnSettings.remove(j); 3388 } else { 3389 j++; 3390 } 3391 } 3392 i++; 3393 } 3394 } 3395 3396 private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { 3397 int id = dest.id; 3398 ArrayList<String> resultTypes = new ArrayList<String>(); 3399 resultTypes.addAll(Arrays.asList(dest.types)); 3400 for (String srcType : src.types) { 3401 if (resultTypes.contains(srcType) == false) resultTypes.add(srcType); 3402 if (srcType.equals(PhoneConstants.APN_TYPE_DEFAULT)) id = src.id; 3403 } 3404 String mmsc = (TextUtils.isEmpty(dest.mmsc) ? src.mmsc : dest.mmsc); 3405 String mmsProxy = (TextUtils.isEmpty(dest.mmsProxy) ? src.mmsProxy : dest.mmsProxy); 3406 String mmsPort = (TextUtils.isEmpty(dest.mmsPort) ? src.mmsPort : dest.mmsPort); 3407 String proxy = (TextUtils.isEmpty(dest.proxy) ? src.proxy : dest.proxy); 3408 String port = (TextUtils.isEmpty(dest.port) ? src.port : dest.port); 3409 String protocol = src.protocol.equals("IPV4V6") ? src.protocol : dest.protocol; 3410 String roamingProtocol = src.roamingProtocol.equals("IPV4V6") ? src.roamingProtocol : 3411 dest.roamingProtocol; 3412 int bearerBitmask = (dest.bearerBitmask == 0 || src.bearerBitmask == 0) ? 3413 0 : (dest.bearerBitmask | src.bearerBitmask); 3414 3415 return new ApnSetting(id, dest.numeric, dest.carrier, dest.apn, 3416 proxy, port, mmsc, mmsProxy, mmsPort, dest.user, dest.password, 3417 dest.authType, resultTypes.toArray(new String[0]), protocol, 3418 roamingProtocol, dest.carrierEnabled, 0, bearerBitmask, dest.profileId, 3419 (dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime, 3420 dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData); 3421 } 3422 3423 /** Return the DC AsyncChannel for the new data connection */ 3424 private DcAsyncChannel createDataConnection() { 3425 if (DBG) log("createDataConnection E"); 3426 3427 int id = mUniqueIdGenerator.getAndIncrement(); 3428 DataConnection conn = DataConnection.makeDataConnection(mPhone, id, 3429 this, mDcTesterFailBringUpAll, mDcc); 3430 mDataConnections.put(id, conn); 3431 DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG); 3432 int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler()); 3433 if (status == AsyncChannel.STATUS_SUCCESSFUL) { 3434 mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac); 3435 } else { 3436 loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status); 3437 } 3438 3439 if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn); 3440 return dcac; 3441 } 3442 3443 private void destroyDataConnections() { 3444 if(mDataConnections != null) { 3445 if (DBG) log("destroyDataConnections: clear mDataConnectionList"); 3446 mDataConnections.clear(); 3447 } else { 3448 if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); 3449 } 3450 } 3451 3452 /** 3453 * Build a list of APNs to be used to create PDP's. 3454 * 3455 * @param requestedApnType 3456 * @return waitingApns list to be used to create PDP 3457 * error when waitingApns.isEmpty() 3458 */ 3459 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) { 3460 if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); 3461 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); 3462 3463 if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) { 3464 ApnSetting dun = fetchDunApn(); 3465 if (dun != null) { 3466 apnList.add(dun); 3467 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); 3468 return apnList; 3469 } 3470 } 3471 3472 IccRecords r = mIccRecords.get(); 3473 String operator = (r != null) ? r.getOperatorNumeric() : ""; 3474 3475 // This is a workaround for a bug (7305641) where we don't failover to other 3476 // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to 3477 // failover to a provisioning APN, but once we've used their default data 3478 // connection we are locked to it for life. This change allows ATT devices 3479 // to say they don't want to use preferred at all. 3480 boolean usePreferred = true; 3481 try { 3482 usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android. 3483 internal.R.bool.config_dontPreferApn); 3484 } catch (Resources.NotFoundException e) { 3485 if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); 3486 usePreferred = true; 3487 } 3488 if (usePreferred) { 3489 mPreferredApn = getPreferredApn(); 3490 } 3491 if (DBG) { 3492 log("buildWaitingApns: usePreferred=" + usePreferred 3493 + " canSetPreferApn=" + mCanSetPreferApn 3494 + " mPreferredApn=" + mPreferredApn 3495 + " operator=" + operator + " radioTech=" + radioTech 3496 + " IccRecords r=" + r); 3497 } 3498 3499 if (usePreferred && mCanSetPreferApn && mPreferredApn != null && 3500 mPreferredApn.canHandleType(requestedApnType)) { 3501 if (DBG) { 3502 log("buildWaitingApns: Preferred APN:" + operator + ":" 3503 + mPreferredApn.numeric + ":" + mPreferredApn); 3504 } 3505 if (mPreferredApn.numeric.equals(operator)) { 3506 if (ServiceState.bitmaskHasTech(mPreferredApn.bearerBitmask, radioTech)) { 3507 apnList.add(mPreferredApn); 3508 if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); 3509 return apnList; 3510 } else { 3511 if (DBG) log("buildWaitingApns: no preferred APN"); 3512 setPreferredApn(-1); 3513 mPreferredApn = null; 3514 } 3515 } else { 3516 if (DBG) log("buildWaitingApns: no preferred APN"); 3517 setPreferredApn(-1); 3518 mPreferredApn = null; 3519 } 3520 } 3521 if (mAllApnSettings != null) { 3522 if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); 3523 for (ApnSetting apn : mAllApnSettings) { 3524 if (apn.canHandleType(requestedApnType)) { 3525 if (ServiceState.bitmaskHasTech(apn.bearerBitmask, radioTech)) { 3526 if (DBG) log("buildWaitingApns: adding apn=" + apn); 3527 apnList.add(apn); 3528 } else { 3529 if (DBG) { 3530 log("buildWaitingApns: bearerBitmask:" + apn.bearerBitmask + " does " + 3531 "not include radioTech:" + radioTech); 3532 } 3533 } 3534 } else if (DBG) { 3535 log("buildWaitingApns: couldn't handle requested ApnType=" 3536 + requestedApnType); 3537 } 3538 } 3539 } else { 3540 loge("mAllApnSettings is null!"); 3541 } 3542 if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList); 3543 return apnList; 3544 } 3545 3546 private String apnListToString (ArrayList<ApnSetting> apns) { 3547 StringBuilder result = new StringBuilder(); 3548 for (int i = 0, size = apns.size(); i < size; i++) { 3549 result.append('[') 3550 .append(apns.get(i).toString()) 3551 .append(']'); 3552 } 3553 return result.toString(); 3554 } 3555 3556 private void setPreferredApn(int pos) { 3557 if (!mCanSetPreferApn) { 3558 log("setPreferredApn: X !canSEtPreferApn"); 3559 return; 3560 } 3561 3562 String subId = Long.toString(mPhone.getSubId()); 3563 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 3564 log("setPreferredApn: delete"); 3565 ContentResolver resolver = mPhone.getContext().getContentResolver(); 3566 resolver.delete(uri, null, null); 3567 3568 if (pos >= 0) { 3569 log("setPreferredApn: insert"); 3570 ContentValues values = new ContentValues(); 3571 values.put(APN_ID, pos); 3572 resolver.insert(uri, values); 3573 } 3574 } 3575 3576 private ApnSetting getPreferredApn() { 3577 if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { 3578 log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty")); 3579 return null; 3580 } 3581 3582 String subId = Long.toString(mPhone.getSubId()); 3583 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 3584 Cursor cursor = mPhone.getContext().getContentResolver().query( 3585 uri, new String[] { "_id", "name", "apn" }, 3586 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 3587 3588 if (cursor != null) { 3589 mCanSetPreferApn = true; 3590 } else { 3591 mCanSetPreferApn = false; 3592 } 3593 log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor 3594 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); 3595 3596 if (mCanSetPreferApn && cursor.getCount() > 0) { 3597 int pos; 3598 cursor.moveToFirst(); 3599 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); 3600 for(ApnSetting p : mAllApnSettings) { 3601 log("getPreferredApn: apnSetting=" + p); 3602 if (p.id == pos && p.canHandleType(mRequestedApnType)) { 3603 log("getPreferredApn: X found apnSetting" + p); 3604 cursor.close(); 3605 return p; 3606 } 3607 } 3608 } 3609 3610 if (cursor != null) { 3611 cursor.close(); 3612 } 3613 3614 log("getPreferredApn: X not found"); 3615 return null; 3616 } 3617 3618 @Override 3619 public void handleMessage (Message msg) { 3620 if (VDBG) log("handleMessage msg=" + msg); 3621 3622 switch (msg.what) { 3623 case DctConstants.EVENT_RECORDS_LOADED: 3624 // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on 3625 // onSubscriptionsChanged() when a valid subId is available. 3626 int subId = mPhone.getSubId(); 3627 if (SubscriptionManager.isValidSubscriptionId(subId)) { 3628 onRecordsLoadedOrSubIdChanged(); 3629 } else { 3630 log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId); 3631 } 3632 break; 3633 3634 case DctConstants.EVENT_DATA_CONNECTION_DETACHED: 3635 onDataConnectionDetached(); 3636 break; 3637 3638 case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: 3639 onDataConnectionAttached(); 3640 break; 3641 3642 case DctConstants.EVENT_DO_RECOVERY: 3643 doRecovery(); 3644 break; 3645 3646 case DctConstants.EVENT_APN_CHANGED: 3647 onApnChanged(); 3648 break; 3649 3650 case DctConstants.EVENT_PS_RESTRICT_ENABLED: 3651 /** 3652 * We don't need to explicitly to tear down the PDP context 3653 * when PS restricted is enabled. The base band will deactive 3654 * PDP context and notify us with PDP_CONTEXT_CHANGED. 3655 * But we should stop the network polling and prevent reset PDP. 3656 */ 3657 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); 3658 stopNetStatPoll(); 3659 stopDataStallAlarm(); 3660 mIsPsRestricted = true; 3661 break; 3662 3663 case DctConstants.EVENT_PS_RESTRICT_DISABLED: 3664 /** 3665 * When PS restrict is removed, we need setup PDP connection if 3666 * PDP connection is down. 3667 */ 3668 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); 3669 mIsPsRestricted = false; 3670 if (isConnected()) { 3671 startNetStatPoll(); 3672 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 3673 } else { 3674 // TODO: Should all PDN states be checked to fail? 3675 if (mState == DctConstants.State.FAILED) { 3676 cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED); 3677 mReregisterOnReconnectFailure = false; 3678 } 3679 ApnContext apnContext = mApnContextsById.get(DctConstants.APN_DEFAULT_ID); 3680 if (apnContext != null) { 3681 apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); 3682 trySetupData(apnContext); 3683 } else { 3684 loge("**** Default ApnContext not found ****"); 3685 if (Build.IS_DEBUGGABLE) { 3686 throw new RuntimeException("Default ApnContext not found"); 3687 } 3688 } 3689 } 3690 break; 3691 3692 case DctConstants.EVENT_TRY_SETUP_DATA: 3693 if (msg.obj instanceof ApnContext) { 3694 onTrySetupData((ApnContext)msg.obj); 3695 } else if (msg.obj instanceof String) { 3696 onTrySetupData((String)msg.obj); 3697 } else { 3698 loge("EVENT_TRY_SETUP request w/o apnContext or String"); 3699 } 3700 break; 3701 3702 case DctConstants.EVENT_CLEAN_UP_CONNECTION: 3703 boolean tearDown = (msg.arg1 == 0) ? false : true; 3704 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown); 3705 if (msg.obj instanceof ApnContext) { 3706 cleanUpConnection(tearDown, (ApnContext)msg.obj); 3707 } else { 3708 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj); 3709 } 3710 break; 3711 case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: { 3712 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 3713 onSetInternalDataEnabled(enabled, (Message) msg.obj); 3714 break; 3715 } 3716 case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: 3717 if ((msg.obj != null) && (msg.obj instanceof String == false)) { 3718 msg.obj = null; 3719 } 3720 onCleanUpAllConnections((String) msg.obj); 3721 break; 3722 3723 case DctConstants.EVENT_DATA_RAT_CHANGED: 3724 if (mPhone.getServiceState().getRilDataRadioTechnology() 3725 == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { 3726 // unknown rat is an exception for data rat change. It's only received when out 3727 // of service and is not applicable for apn bearer bitmask. We should bypass the 3728 // check of waiting apn list and keep the data connection on, and no need to 3729 // setup a new one. 3730 break; 3731 } 3732 cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED); 3733 //May new Network allow setupData, so try it here 3734 setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED, 3735 RetryFailures.ONLY_ON_CHANGE); 3736 break; 3737 3738 case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: 3739 // Check message sender intended to clear the current spinner. 3740 if (mProvisioningSpinner == msg.obj) { 3741 mProvisioningSpinner.dismiss(); 3742 mProvisioningSpinner = null; 3743 } 3744 break; 3745 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 3746 log("DISCONNECTED_CONNECTED: msg=" + msg); 3747 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj; 3748 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync()); 3749 dcac.disconnected(); 3750 break; 3751 } 3752 case DctConstants.EVENT_ENABLE_NEW_APN: 3753 onEnableApn(msg.arg1, msg.arg2); 3754 break; 3755 3756 case DctConstants.EVENT_DATA_STALL_ALARM: 3757 onDataStallAlarm(msg.arg1); 3758 break; 3759 3760 case DctConstants.EVENT_ROAMING_OFF: 3761 onDataRoamingOff(); 3762 break; 3763 3764 case DctConstants.EVENT_ROAMING_ON: 3765 onDataRoamingOnOrSettingsChanged(); 3766 break; 3767 3768 case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE: 3769 onDeviceProvisionedChange(); 3770 break; 3771 3772 case DctConstants.EVENT_REDIRECTION_DETECTED: 3773 String url = (String) msg.obj; 3774 log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url); 3775 onDataConnectionRedirected(url); 3776 3777 case DctConstants.EVENT_RADIO_AVAILABLE: 3778 onRadioAvailable(); 3779 break; 3780 3781 case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE: 3782 onRadioOffOrNotAvailable(); 3783 break; 3784 3785 case DctConstants.EVENT_DATA_SETUP_COMPLETE: 3786 onDataSetupComplete((AsyncResult) msg.obj); 3787 break; 3788 3789 case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR: 3790 onDataSetupCompleteError((AsyncResult) msg.obj); 3791 break; 3792 3793 case DctConstants.EVENT_DISCONNECT_DONE: 3794 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg); 3795 onDisconnectDone((AsyncResult) msg.obj); 3796 break; 3797 3798 case DctConstants.EVENT_DISCONNECT_DC_RETRYING: 3799 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg); 3800 onDisconnectDcRetrying((AsyncResult) msg.obj); 3801 break; 3802 3803 case DctConstants.EVENT_VOICE_CALL_STARTED: 3804 onVoiceCallStarted(); 3805 break; 3806 3807 case DctConstants.EVENT_VOICE_CALL_ENDED: 3808 onVoiceCallEnded(); 3809 break; 3810 3811 case DctConstants.EVENT_RESET_DONE: { 3812 if (DBG) log("EVENT_RESET_DONE"); 3813 onResetDone((AsyncResult) msg.obj); 3814 break; 3815 } 3816 case DctConstants.CMD_SET_USER_DATA_ENABLE: { 3817 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 3818 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled); 3819 onSetUserDataEnabled(enabled); 3820 break; 3821 } 3822 // TODO - remove 3823 case DctConstants.CMD_SET_DEPENDENCY_MET: { 3824 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false; 3825 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met); 3826 Bundle bundle = msg.getData(); 3827 if (bundle != null) { 3828 String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); 3829 if (apnType != null) { 3830 onSetDependencyMet(apnType, met); 3831 } 3832 } 3833 break; 3834 } 3835 case DctConstants.CMD_SET_POLICY_DATA_ENABLE: { 3836 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 3837 onSetPolicyDataEnabled(enabled); 3838 break; 3839 } 3840 case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: { 3841 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1; 3842 if (DBG) { 3843 log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " 3844 + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); 3845 } 3846 if (sEnableFailFastRefCounter < 0) { 3847 final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " 3848 + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0"; 3849 loge(s); 3850 sEnableFailFastRefCounter = 0; 3851 } 3852 final boolean enabled = sEnableFailFastRefCounter > 0; 3853 if (DBG) { 3854 log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled 3855 + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); 3856 } 3857 if (mFailFast != enabled) { 3858 mFailFast = enabled; 3859 3860 mDataStallDetectionEnabled = !enabled; 3861 if (mDataStallDetectionEnabled 3862 && (getOverallState() == DctConstants.State.CONNECTED) 3863 && (!mInVoiceCall || 3864 mPhone.getServiceStateTracker() 3865 .isConcurrentVoiceAndDataAllowed())) { 3866 if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall"); 3867 stopDataStallAlarm(); 3868 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 3869 } else { 3870 if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall"); 3871 stopDataStallAlarm(); 3872 } 3873 } 3874 3875 break; 3876 } 3877 case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: { 3878 Bundle bundle = msg.getData(); 3879 if (bundle != null) { 3880 try { 3881 mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY); 3882 } catch(ClassCastException e) { 3883 loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e); 3884 mProvisioningUrl = null; 3885 } 3886 } 3887 if (TextUtils.isEmpty(mProvisioningUrl)) { 3888 loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring"); 3889 mIsProvisioning = false; 3890 mProvisioningUrl = null; 3891 } else { 3892 loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl); 3893 mIsProvisioning = true; 3894 startProvisioningApnAlarm(); 3895 } 3896 break; 3897 } 3898 case DctConstants.EVENT_PROVISIONING_APN_ALARM: { 3899 if (DBG) log("EVENT_PROVISIONING_APN_ALARM"); 3900 ApnContext apnCtx = mApnContextsById.get(DctConstants.APN_DEFAULT_ID); 3901 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) { 3902 if (mProvisioningApnAlarmTag == msg.arg1) { 3903 if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting"); 3904 mIsProvisioning = false; 3905 mProvisioningUrl = null; 3906 stopProvisioningApnAlarm(); 3907 sendCleanUpConnection(true, apnCtx); 3908 } else { 3909 if (DBG) { 3910 log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag," 3911 + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag 3912 + " != arg1:" + msg.arg1); 3913 } 3914 } 3915 } else { 3916 if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore"); 3917 } 3918 break; 3919 } 3920 case DctConstants.CMD_IS_PROVISIONING_APN: { 3921 if (DBG) log("CMD_IS_PROVISIONING_APN"); 3922 boolean isProvApn; 3923 try { 3924 String apnType = null; 3925 Bundle bundle = msg.getData(); 3926 if (bundle != null) { 3927 apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); 3928 } 3929 if (TextUtils.isEmpty(apnType)) { 3930 loge("CMD_IS_PROVISIONING_APN: apnType is empty"); 3931 isProvApn = false; 3932 } else { 3933 isProvApn = isProvisioningApn(apnType); 3934 } 3935 } catch (ClassCastException e) { 3936 loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring"); 3937 isProvApn = false; 3938 } 3939 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn); 3940 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN, 3941 isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED); 3942 break; 3943 } 3944 case DctConstants.EVENT_ICC_CHANGED: { 3945 onUpdateIcc(); 3946 break; 3947 } 3948 case DctConstants.EVENT_RESTART_RADIO: { 3949 restartRadio(); 3950 break; 3951 } 3952 case DctConstants.CMD_NET_STAT_POLL: { 3953 if (msg.arg1 == DctConstants.ENABLED) { 3954 handleStartNetStatPoll((DctConstants.Activity)msg.obj); 3955 } else if (msg.arg1 == DctConstants.DISABLED) { 3956 handleStopNetStatPoll((DctConstants.Activity)msg.obj); 3957 } 3958 break; 3959 } 3960 case DctConstants.EVENT_DATA_STATE_CHANGED: { 3961 // no longer do anything, but still registered - clean up log 3962 // TODO - why are we still registering? 3963 break; 3964 } 3965 case DctConstants.EVENT_PCO_DATA_RECEIVED: { 3966 handlePcoData((AsyncResult)msg.obj); 3967 break; 3968 } 3969 case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED: 3970 onSetCarrierDataEnabled((AsyncResult) msg.obj); 3971 break; 3972 case DctConstants.EVENT_DATA_RECONNECT: 3973 onDataReconnect(msg.getData()); 3974 break; 3975 default: 3976 Rlog.e("DcTracker", "Unhandled event=" + msg); 3977 break; 3978 3979 } 3980 } 3981 3982 private int getApnProfileID(String apnType) { 3983 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 3984 return RILConstants.DATA_PROFILE_IMS; 3985 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) { 3986 return RILConstants.DATA_PROFILE_FOTA; 3987 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) { 3988 return RILConstants.DATA_PROFILE_CBS; 3989 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IA)) { 3990 return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now 3991 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_DUN)) { 3992 return RILConstants.DATA_PROFILE_TETHERED; 3993 } else { 3994 return RILConstants.DATA_PROFILE_DEFAULT; 3995 } 3996 } 3997 3998 private int getCellLocationId() { 3999 int cid = -1; 4000 CellLocation loc = mPhone.getCellLocation(); 4001 4002 if (loc != null) { 4003 if (loc instanceof GsmCellLocation) { 4004 cid = ((GsmCellLocation)loc).getCid(); 4005 } else if (loc instanceof CdmaCellLocation) { 4006 cid = ((CdmaCellLocation)loc).getBaseStationId(); 4007 } 4008 } 4009 return cid; 4010 } 4011 4012 private IccRecords getUiccRecords(int appFamily) { 4013 return mUiccController.getIccRecords(mPhone.getPhoneId(), appFamily); 4014 } 4015 4016 4017 private void onUpdateIcc() { 4018 if (mUiccController == null ) { 4019 return; 4020 } 4021 4022 IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP); 4023 4024 IccRecords r = mIccRecords.get(); 4025 if (r != newIccRecords) { 4026 if (r != null) { 4027 log("Removing stale icc objects."); 4028 r.unregisterForRecordsLoaded(this); 4029 mIccRecords.set(null); 4030 } 4031 if (newIccRecords != null) { 4032 if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { 4033 log("New records found."); 4034 mIccRecords.set(newIccRecords); 4035 newIccRecords.registerForRecordsLoaded( 4036 this, DctConstants.EVENT_RECORDS_LOADED, null); 4037 } 4038 } else { 4039 onSimNotReady(); 4040 } 4041 } 4042 } 4043 4044 public void update() { 4045 log("update sub = " + mPhone.getSubId()); 4046 log("update(): Active DDS, register for all events now!"); 4047 onUpdateIcc(); 4048 4049 mDataEnabledSettings.setUserDataEnabled(getDataEnabled()); 4050 mAutoAttachOnCreation.set(false); 4051 4052 ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider(); 4053 } 4054 4055 public void cleanUpAllConnections(String cause) { 4056 cleanUpAllConnections(cause, null); 4057 } 4058 4059 public void updateRecords() { 4060 onUpdateIcc(); 4061 } 4062 4063 public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) { 4064 log("cleanUpAllConnections"); 4065 if (disconnectAllCompleteMsg != null) { 4066 mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg); 4067 } 4068 4069 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); 4070 msg.obj = cause; 4071 sendMessage(msg); 4072 } 4073 4074 private void notifyDataDisconnectComplete() { 4075 log("notifyDataDisconnectComplete"); 4076 for (Message m: mDisconnectAllCompleteMsgList) { 4077 m.sendToTarget(); 4078 } 4079 mDisconnectAllCompleteMsgList.clear(); 4080 } 4081 4082 4083 private void notifyAllDataDisconnected() { 4084 sEnableFailFastRefCounter = 0; 4085 mFailFast = false; 4086 mAllDataDisconnectedRegistrants.notifyRegistrants(); 4087 } 4088 4089 public void registerForAllDataDisconnected(Handler h, int what, Object obj) { 4090 mAllDataDisconnectedRegistrants.addUnique(h, what, obj); 4091 4092 if (isDisconnected()) { 4093 log("notify All Data Disconnected"); 4094 notifyAllDataDisconnected(); 4095 } 4096 } 4097 4098 public void unregisterForAllDataDisconnected(Handler h) { 4099 mAllDataDisconnectedRegistrants.remove(h); 4100 } 4101 4102 public void registerForDataEnabledChanged(Handler h, int what, Object obj) { 4103 mDataEnabledSettings.registerForDataEnabledChanged(h, what, obj); 4104 } 4105 4106 public void unregisterForDataEnabledChanged(Handler h) { 4107 mDataEnabledSettings.unregisterForDataEnabledChanged(h); 4108 } 4109 4110 private void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) { 4111 synchronized (mDataEnabledSettings) { 4112 if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled); 4113 boolean sendOnComplete = true; 4114 4115 mDataEnabledSettings.setInternalDataEnabled(enabled); 4116 if (enabled) { 4117 log("onSetInternalDataEnabled: changed to enabled, try to setup data call"); 4118 onTrySetupData(Phone.REASON_DATA_ENABLED); 4119 } else { 4120 sendOnComplete = false; 4121 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections"); 4122 cleanUpAllConnections(Phone.REASON_DATA_DISABLED, onCompleteMsg); 4123 } 4124 4125 if (sendOnComplete) { 4126 if (onCompleteMsg != null) { 4127 onCompleteMsg.sendToTarget(); 4128 } 4129 } 4130 } 4131 } 4132 4133 public boolean setInternalDataEnabled(boolean enable) { 4134 return setInternalDataEnabled(enable, null); 4135 } 4136 4137 public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) { 4138 if (DBG) log("setInternalDataEnabled(" + enable + ")"); 4139 4140 Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg); 4141 msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 4142 sendMessage(msg); 4143 return true; 4144 } 4145 4146 private void log(String s) { 4147 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 4148 } 4149 4150 private void loge(String s) { 4151 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 4152 } 4153 4154 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4155 pw.println("DcTracker:"); 4156 pw.println(" RADIO_TESTS=" + RADIO_TESTS); 4157 pw.println(" mDataEnabledSettings=" + mDataEnabledSettings); 4158 pw.println(" isDataAllowed=" + isDataAllowed(null)); 4159 pw.flush(); 4160 pw.println(" mRequestedApnType=" + mRequestedApnType); 4161 pw.println(" mPhone=" + mPhone.getPhoneName()); 4162 pw.println(" mActivity=" + mActivity); 4163 pw.println(" mState=" + mState); 4164 pw.println(" mTxPkts=" + mTxPkts); 4165 pw.println(" mRxPkts=" + mRxPkts); 4166 pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod); 4167 pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled); 4168 pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum); 4169 pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag); 4170 pw.println(" mDataStallDetectionEnabled=" + mDataStallDetectionEnabled); 4171 pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv); 4172 pw.println(" mNoRecvPollCount=" + mNoRecvPollCount); 4173 pw.println(" mResolver=" + mResolver); 4174 pw.println(" mIsWifiConnected=" + mIsWifiConnected); 4175 pw.println(" mReconnectIntent=" + mReconnectIntent); 4176 pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation.get()); 4177 pw.println(" mIsScreenOn=" + mIsScreenOn); 4178 pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); 4179 pw.flush(); 4180 pw.println(" ***************************************"); 4181 DcController dcc = mDcc; 4182 if (dcc != null) { 4183 dcc.dump(fd, pw, args); 4184 } else { 4185 pw.println(" mDcc=null"); 4186 } 4187 pw.println(" ***************************************"); 4188 HashMap<Integer, DataConnection> dcs = mDataConnections; 4189 if (dcs != null) { 4190 Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet(); 4191 pw.println(" mDataConnections: count=" + mDcSet.size()); 4192 for (Entry<Integer, DataConnection> entry : mDcSet) { 4193 pw.printf(" *** mDataConnection[%d] \n", entry.getKey()); 4194 entry.getValue().dump(fd, pw, args); 4195 } 4196 } else { 4197 pw.println("mDataConnections=null"); 4198 } 4199 pw.println(" ***************************************"); 4200 pw.flush(); 4201 HashMap<String, Integer> apnToDcId = mApnToDataConnectionId; 4202 if (apnToDcId != null) { 4203 Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet(); 4204 pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size()); 4205 for (Entry<String, Integer> entry : apnToDcIdSet) { 4206 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue()); 4207 } 4208 } else { 4209 pw.println("mApnToDataConnectionId=null"); 4210 } 4211 pw.println(" ***************************************"); 4212 pw.flush(); 4213 ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts; 4214 if (apnCtxs != null) { 4215 Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet(); 4216 pw.println(" mApnContexts size=" + apnCtxsSet.size()); 4217 for (Entry<String, ApnContext> entry : apnCtxsSet) { 4218 entry.getValue().dump(fd, pw, args); 4219 } 4220 pw.println(" ***************************************"); 4221 } else { 4222 pw.println(" mApnContexts=null"); 4223 } 4224 pw.flush(); 4225 ArrayList<ApnSetting> apnSettings = mAllApnSettings; 4226 if (apnSettings != null) { 4227 pw.println(" mAllApnSettings size=" + apnSettings.size()); 4228 for (int i=0; i < apnSettings.size(); i++) { 4229 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i)); 4230 } 4231 pw.flush(); 4232 } else { 4233 pw.println(" mAllApnSettings=null"); 4234 } 4235 pw.println(" mPreferredApn=" + mPreferredApn); 4236 pw.println(" mIsPsRestricted=" + mIsPsRestricted); 4237 pw.println(" mIsDisposed=" + mIsDisposed); 4238 pw.println(" mIntentReceiver=" + mIntentReceiver); 4239 pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); 4240 pw.println(" canSetPreferApn=" + mCanSetPreferApn); 4241 pw.println(" mApnObserver=" + mApnObserver); 4242 pw.println(" getOverallState=" + getOverallState()); 4243 pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap); 4244 pw.println(" mAttached=" + mAttached.get()); 4245 pw.flush(); 4246 } 4247 4248 public String[] getPcscfAddress(String apnType) { 4249 log("getPcscfAddress()"); 4250 ApnContext apnContext = null; 4251 4252 if(apnType == null){ 4253 log("apnType is null, return null"); 4254 return null; 4255 } 4256 4257 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_EMERGENCY)) { 4258 apnContext = mApnContextsById.get(DctConstants.APN_EMERGENCY_ID); 4259 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 4260 apnContext = mApnContextsById.get(DctConstants.APN_IMS_ID); 4261 } else { 4262 log("apnType is invalid, return null"); 4263 return null; 4264 } 4265 4266 if (apnContext == null) { 4267 log("apnContext is null, return null"); 4268 return null; 4269 } 4270 4271 DcAsyncChannel dcac = apnContext.getDcAc(); 4272 String[] result = null; 4273 4274 if (dcac != null) { 4275 result = dcac.getPcscfAddr(); 4276 4277 for (int i = 0; i < result.length; i++) { 4278 log("Pcscf[" + i + "]: " + result[i]); 4279 } 4280 return result; 4281 } 4282 return null; 4283 } 4284 4285 /** 4286 * Read APN configuration from Telephony.db for Emergency APN 4287 * All opertors recognize the connection request for EPDN based on APN type 4288 * PLMN name,APN name are not mandatory parameters 4289 */ 4290 private void initEmergencyApnSetting() { 4291 // Operator Numeric is not available when sim records are not loaded. 4292 // Query Telephony.db with APN type as EPDN request does not 4293 // require APN name, plmn and all operators support same APN config. 4294 // DB will contain only one entry for Emergency APN 4295 String selection = "type=\"emergency\""; 4296 Cursor cursor = mPhone.getContext().getContentResolver().query( 4297 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 4298 4299 if (cursor != null) { 4300 if (cursor.getCount() > 0) { 4301 if (cursor.moveToFirst()) { 4302 mEmergencyApn = makeApnSetting(cursor); 4303 } 4304 } 4305 cursor.close(); 4306 } 4307 } 4308 4309 /** 4310 * Add the Emergency APN settings to APN settings list 4311 */ 4312 private void addEmergencyApnSetting() { 4313 if(mEmergencyApn != null) { 4314 if(mAllApnSettings == null) { 4315 mAllApnSettings = new ArrayList<ApnSetting>(); 4316 } else { 4317 boolean hasEmergencyApn = false; 4318 for (ApnSetting apn : mAllApnSettings) { 4319 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) { 4320 hasEmergencyApn = true; 4321 break; 4322 } 4323 } 4324 4325 if(hasEmergencyApn == false) { 4326 mAllApnSettings.add(mEmergencyApn); 4327 } else { 4328 log("addEmergencyApnSetting - E-APN setting is already present"); 4329 } 4330 } 4331 } 4332 } 4333 4334 private boolean containsAllApns(ArrayList<ApnSetting> oldApnList, 4335 ArrayList<ApnSetting> newApnList) { 4336 for (ApnSetting newApnSetting : newApnList) { 4337 boolean canHandle = false; 4338 for (ApnSetting oldApnSetting : oldApnList) { 4339 // Make sure at least one of the APN from old list can cover the new APN 4340 if (oldApnSetting.equals(newApnSetting, 4341 mPhone.getServiceState().getDataRoamingFromRegistration())) { 4342 canHandle = true; 4343 break; 4344 } 4345 } 4346 if (!canHandle) return false; 4347 } 4348 return true; 4349 } 4350 4351 private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) { 4352 if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown); 4353 if (mAllApnSettings != null && mAllApnSettings.isEmpty()) { 4354 cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED); 4355 } else { 4356 for (ApnContext apnContext : mApnContexts.values()) { 4357 ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns(); 4358 ArrayList<ApnSetting> waitingApns = buildWaitingApns( 4359 apnContext.getApnType(), 4360 mPhone.getServiceState().getRilDataRadioTechnology()); 4361 if (VDBG) log("new waitingApns:" + waitingApns); 4362 if ((currentWaitingApns != null) 4363 && ((waitingApns.size() != currentWaitingApns.size()) 4364 // Check if the existing waiting APN list can cover the newly built APN 4365 // list. If yes, then we don't need to tear down the existing data call. 4366 // TODO: We probably need to rebuild APN list when roaming status changes. 4367 || !containsAllApns(currentWaitingApns, waitingApns))) { 4368 if (VDBG) log("new waiting apn is different for " + apnContext); 4369 apnContext.setWaitingApns(waitingApns); 4370 if (!apnContext.isDisconnected()) { 4371 if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext); 4372 apnContext.setReason(reason); 4373 cleanUpConnection(true, apnContext); 4374 } 4375 } 4376 } 4377 } 4378 4379 if (!isConnected()) { 4380 stopNetStatPoll(); 4381 stopDataStallAlarm(); 4382 } 4383 4384 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 4385 4386 if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount); 4387 if (tearDown && mDisconnectPendingCount == 0) { 4388 notifyDataDisconnectComplete(); 4389 notifyAllDataDisconnected(); 4390 } 4391 } 4392 4393 /** 4394 * Polling stuff 4395 */ 4396 private void resetPollStats() { 4397 mTxPkts = -1; 4398 mRxPkts = -1; 4399 mNetStatPollPeriod = POLL_NETSTAT_MILLIS; 4400 } 4401 4402 private void startNetStatPoll() { 4403 if (getOverallState() == DctConstants.State.CONNECTED 4404 && mNetStatPollEnabled == false) { 4405 if (DBG) { 4406 log("startNetStatPoll"); 4407 } 4408 resetPollStats(); 4409 mNetStatPollEnabled = true; 4410 mPollNetStat.run(); 4411 } 4412 if (mPhone != null) { 4413 mPhone.notifyDataActivity(); 4414 } 4415 } 4416 4417 private void stopNetStatPoll() { 4418 mNetStatPollEnabled = false; 4419 removeCallbacks(mPollNetStat); 4420 if (DBG) { 4421 log("stopNetStatPoll"); 4422 } 4423 4424 // To sync data activity icon in the case of switching data connection to send MMS. 4425 if (mPhone != null) { 4426 mPhone.notifyDataActivity(); 4427 } 4428 } 4429 4430 public void sendStartNetStatPoll(DctConstants.Activity activity) { 4431 Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); 4432 msg.arg1 = DctConstants.ENABLED; 4433 msg.obj = activity; 4434 sendMessage(msg); 4435 } 4436 4437 private void handleStartNetStatPoll(DctConstants.Activity activity) { 4438 startNetStatPoll(); 4439 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 4440 setActivity(activity); 4441 } 4442 4443 public void sendStopNetStatPoll(DctConstants.Activity activity) { 4444 Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); 4445 msg.arg1 = DctConstants.DISABLED; 4446 msg.obj = activity; 4447 sendMessage(msg); 4448 } 4449 4450 private void handleStopNetStatPoll(DctConstants.Activity activity) { 4451 stopNetStatPoll(); 4452 stopDataStallAlarm(); 4453 setActivity(activity); 4454 } 4455 4456 private void updateDataActivity() { 4457 long sent, received; 4458 4459 DctConstants.Activity newActivity; 4460 4461 TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); 4462 TxRxSum curTxRxSum = new TxRxSum(); 4463 curTxRxSum.updateTxRxSum(); 4464 mTxPkts = curTxRxSum.txPkts; 4465 mRxPkts = curTxRxSum.rxPkts; 4466 4467 if (VDBG) { 4468 log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); 4469 } 4470 4471 if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { 4472 sent = mTxPkts - preTxRxSum.txPkts; 4473 received = mRxPkts - preTxRxSum.rxPkts; 4474 4475 if (VDBG) 4476 log("updateDataActivity: sent=" + sent + " received=" + received); 4477 if (sent > 0 && received > 0) { 4478 newActivity = DctConstants.Activity.DATAINANDOUT; 4479 } else if (sent > 0 && received == 0) { 4480 newActivity = DctConstants.Activity.DATAOUT; 4481 } else if (sent == 0 && received > 0) { 4482 newActivity = DctConstants.Activity.DATAIN; 4483 } else { 4484 newActivity = (mActivity == DctConstants.Activity.DORMANT) ? 4485 mActivity : DctConstants.Activity.NONE; 4486 } 4487 4488 if (mActivity != newActivity && mIsScreenOn) { 4489 if (VDBG) 4490 log("updateDataActivity: newActivity=" + newActivity); 4491 mActivity = newActivity; 4492 mPhone.notifyDataActivity(); 4493 } 4494 } 4495 } 4496 4497 private void handlePcoData(AsyncResult ar) { 4498 if (ar.exception != null) { 4499 Rlog.e(LOG_TAG, "PCO_DATA exception: " + ar.exception); 4500 return; 4501 } 4502 PcoData pcoData = (PcoData)(ar.result); 4503 ArrayList<DataConnection> dcList = new ArrayList<>(); 4504 DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid); 4505 if (temp != null) { 4506 dcList.add(temp); 4507 } 4508 if (dcList.size() == 0) { 4509 Rlog.e(LOG_TAG, "PCO_DATA for unknown cid: " + pcoData.cid + ", inferring"); 4510 for (DataConnection dc : mDataConnections.values()) { 4511 final int cid = dc.getCid(); 4512 if (cid == pcoData.cid) { 4513 if (VDBG) Rlog.d(LOG_TAG, " found " + dc); 4514 dcList.clear(); 4515 dcList.add(dc); 4516 break; 4517 } 4518 // check if this dc is still connecting 4519 if (cid == -1) { 4520 for (ApnContext apnContext : dc.mApnContexts.keySet()) { 4521 if (apnContext.getState() == DctConstants.State.CONNECTING) { 4522 if (VDBG) Rlog.d(LOG_TAG, " found potential " + dc); 4523 dcList.add(dc); 4524 break; 4525 } 4526 } 4527 } 4528 } 4529 } 4530 if (dcList.size() == 0) { 4531 Rlog.e(LOG_TAG, "PCO_DATA - couldn't infer cid"); 4532 return; 4533 } 4534 for (DataConnection dc : dcList) { 4535 if (dc.mApnContexts.size() == 0) { 4536 break; 4537 } 4538 // send one out for each apn type in play 4539 for (ApnContext apnContext : dc.mApnContexts.keySet()) { 4540 String apnType = apnContext.getApnType(); 4541 4542 final Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE); 4543 intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnType); 4544 intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, pcoData.bearerProto); 4545 intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, pcoData.pcoId); 4546 intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, pcoData.contents); 4547 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); 4548 } 4549 } 4550 } 4551 4552 /** 4553 * Data-Stall 4554 */ 4555 // Recovery action taken in case of data stall 4556 private static class RecoveryAction { 4557 public static final int GET_DATA_CALL_LIST = 0; 4558 public static final int CLEANUP = 1; 4559 public static final int REREGISTER = 2; 4560 public static final int RADIO_RESTART = 3; 4561 public static final int RADIO_RESTART_WITH_PROP = 4; 4562 4563 private static boolean isAggressiveRecovery(int value) { 4564 return ((value == RecoveryAction.CLEANUP) || 4565 (value == RecoveryAction.REREGISTER) || 4566 (value == RecoveryAction.RADIO_RESTART) || 4567 (value == RecoveryAction.RADIO_RESTART_WITH_PROP)); 4568 } 4569 } 4570 4571 private int getRecoveryAction() { 4572 int action = Settings.System.getInt(mResolver, 4573 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST); 4574 if (VDBG_STALL) log("getRecoveryAction: " + action); 4575 return action; 4576 } 4577 4578 private void putRecoveryAction(int action) { 4579 Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action); 4580 if (VDBG_STALL) log("putRecoveryAction: " + action); 4581 } 4582 4583 private void doRecovery() { 4584 if (getOverallState() == DctConstants.State.CONNECTED) { 4585 // Go through a series of recovery steps, each action transitions to the next action 4586 final int recoveryAction = getRecoveryAction(); 4587 TelephonyMetrics.getInstance().writeDataStallEvent(mPhone.getPhoneId(), recoveryAction); 4588 switch (recoveryAction) { 4589 case RecoveryAction.GET_DATA_CALL_LIST: 4590 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, 4591 mSentSinceLastRecv); 4592 if (DBG) log("doRecovery() get data call list"); 4593 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED)); 4594 putRecoveryAction(RecoveryAction.CLEANUP); 4595 break; 4596 case RecoveryAction.CLEANUP: 4597 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv); 4598 if (DBG) log("doRecovery() cleanup all connections"); 4599 cleanUpAllConnections(Phone.REASON_PDP_RESET); 4600 putRecoveryAction(RecoveryAction.REREGISTER); 4601 break; 4602 case RecoveryAction.REREGISTER: 4603 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, 4604 mSentSinceLastRecv); 4605 if (DBG) log("doRecovery() re-register"); 4606 mPhone.getServiceStateTracker().reRegisterNetwork(null); 4607 putRecoveryAction(RecoveryAction.RADIO_RESTART); 4608 break; 4609 case RecoveryAction.RADIO_RESTART: 4610 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, 4611 mSentSinceLastRecv); 4612 if (DBG) log("restarting radio"); 4613 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP); 4614 restartRadio(); 4615 break; 4616 case RecoveryAction.RADIO_RESTART_WITH_PROP: 4617 // This is in case radio restart has not recovered the data. 4618 // It will set an additional "gsm.radioreset" property to tell 4619 // RIL or system to take further action. 4620 // The implementation of hard reset recovery action is up to OEM product. 4621 // Once RADIO_RESET property is consumed, it is expected to set back 4622 // to false by RIL. 4623 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1); 4624 if (DBG) log("restarting radio with gsm.radioreset to true"); 4625 SystemProperties.set(RADIO_RESET_PROPERTY, "true"); 4626 // give 1 sec so property change can be notified. 4627 try { 4628 Thread.sleep(1000); 4629 } catch (InterruptedException e) {} 4630 restartRadio(); 4631 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 4632 break; 4633 default: 4634 throw new RuntimeException("doRecovery: Invalid recoveryAction=" + 4635 recoveryAction); 4636 } 4637 mSentSinceLastRecv = 0; 4638 } 4639 } 4640 4641 private void updateDataStallInfo() { 4642 long sent, received; 4643 4644 TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); 4645 mDataStallTxRxSum.updateTxRxSum(); 4646 4647 if (VDBG_STALL) { 4648 log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + 4649 " preTxRxSum=" + preTxRxSum); 4650 } 4651 4652 sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; 4653 received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; 4654 4655 if (RADIO_TESTS) { 4656 if (SystemProperties.getBoolean("radio.test.data.stall", false)) { 4657 log("updateDataStallInfo: radio.test.data.stall true received = 0;"); 4658 received = 0; 4659 } 4660 } 4661 if ( sent > 0 && received > 0 ) { 4662 if (VDBG_STALL) log("updateDataStallInfo: IN/OUT"); 4663 mSentSinceLastRecv = 0; 4664 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 4665 } else if (sent > 0 && received == 0) { 4666 if (isPhoneStateIdle()) { 4667 mSentSinceLastRecv += sent; 4668 } else { 4669 mSentSinceLastRecv = 0; 4670 } 4671 if (DBG) { 4672 log("updateDataStallInfo: OUT sent=" + sent + 4673 " mSentSinceLastRecv=" + mSentSinceLastRecv); 4674 } 4675 } else if (sent == 0 && received > 0) { 4676 if (VDBG_STALL) log("updateDataStallInfo: IN"); 4677 mSentSinceLastRecv = 0; 4678 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST); 4679 } else { 4680 if (VDBG_STALL) log("updateDataStallInfo: NONE"); 4681 } 4682 } 4683 4684 private boolean isPhoneStateIdle() { 4685 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) { 4686 Phone phone = PhoneFactory.getPhone(i); 4687 if (phone != null && phone.getState() != PhoneConstants.State.IDLE) { 4688 log("isPhoneStateIdle false: Voice call active on phone " + i); 4689 return false; 4690 } 4691 } 4692 return true; 4693 } 4694 4695 private void onDataStallAlarm(int tag) { 4696 if (mDataStallAlarmTag != tag) { 4697 if (DBG) { 4698 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); 4699 } 4700 return; 4701 } 4702 updateDataStallInfo(); 4703 4704 int hangWatchdogTrigger = Settings.Global.getInt(mResolver, 4705 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, 4706 NUMBER_SENT_PACKETS_OF_HANG); 4707 4708 boolean suspectedStall = DATA_STALL_NOT_SUSPECTED; 4709 if (mSentSinceLastRecv >= hangWatchdogTrigger) { 4710 if (DBG) { 4711 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction()); 4712 } 4713 suspectedStall = DATA_STALL_SUSPECTED; 4714 sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); 4715 } else { 4716 if (VDBG_STALL) { 4717 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + 4718 " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); 4719 } 4720 } 4721 startDataStallAlarm(suspectedStall); 4722 } 4723 4724 private void startDataStallAlarm(boolean suspectedStall) { 4725 int nextAction = getRecoveryAction(); 4726 int delayInMs; 4727 4728 if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) { 4729 // If screen is on or data stall is currently suspected, set the alarm 4730 // with an aggressive timeout. 4731 if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) { 4732 delayInMs = Settings.Global.getInt(mResolver, 4733 Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, 4734 DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT); 4735 } else { 4736 delayInMs = Settings.Global.getInt(mResolver, 4737 Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, 4738 DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT); 4739 } 4740 4741 mDataStallAlarmTag += 1; 4742 if (VDBG_STALL) { 4743 log("startDataStallAlarm: tag=" + mDataStallAlarmTag + 4744 " delay=" + (delayInMs / 1000) + "s"); 4745 } 4746 Intent intent = new Intent(INTENT_DATA_STALL_ALARM); 4747 intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag); 4748 mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, 4749 PendingIntent.FLAG_UPDATE_CURRENT); 4750 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, 4751 SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); 4752 } else { 4753 if (VDBG_STALL) { 4754 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag); 4755 } 4756 } 4757 } 4758 4759 private void stopDataStallAlarm() { 4760 if (VDBG_STALL) { 4761 log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + 4762 " mDataStallAlarmIntent=" + mDataStallAlarmIntent); 4763 } 4764 mDataStallAlarmTag += 1; 4765 if (mDataStallAlarmIntent != null) { 4766 mAlarmManager.cancel(mDataStallAlarmIntent); 4767 mDataStallAlarmIntent = null; 4768 } 4769 } 4770 4771 private void restartDataStallAlarm() { 4772 if (isConnected() == false) return; 4773 // To be called on screen status change. 4774 // Do not cancel the alarm if it is set with aggressive timeout. 4775 int nextAction = getRecoveryAction(); 4776 4777 if (RecoveryAction.isAggressiveRecovery(nextAction)) { 4778 if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm."); 4779 return; 4780 } 4781 if (VDBG_STALL) log("restartDataStallAlarm: stop then start."); 4782 stopDataStallAlarm(); 4783 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 4784 } 4785 4786 /** 4787 * Provisioning APN 4788 */ 4789 private void onActionIntentProvisioningApnAlarm(Intent intent) { 4790 if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction()); 4791 Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM, 4792 intent.getAction()); 4793 msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0); 4794 sendMessage(msg); 4795 } 4796 4797 private void startProvisioningApnAlarm() { 4798 int delayInMs = Settings.Global.getInt(mResolver, 4799 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, 4800 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT); 4801 if (Build.IS_DEBUGGABLE) { 4802 // Allow debug code to use a system property to provide another value 4803 String delayInMsStrg = Integer.toString(delayInMs); 4804 delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg); 4805 try { 4806 delayInMs = Integer.parseInt(delayInMsStrg); 4807 } catch (NumberFormatException e) { 4808 loge("startProvisioningApnAlarm: e=" + e); 4809 } 4810 } 4811 mProvisioningApnAlarmTag += 1; 4812 if (DBG) { 4813 log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag + 4814 " delay=" + (delayInMs / 1000) + "s"); 4815 } 4816 Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM); 4817 intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag); 4818 mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, 4819 PendingIntent.FLAG_UPDATE_CURRENT); 4820 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 4821 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent); 4822 } 4823 4824 private void stopProvisioningApnAlarm() { 4825 if (DBG) { 4826 log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag + 4827 " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent); 4828 } 4829 mProvisioningApnAlarmTag += 1; 4830 if (mProvisioningApnAlarmIntent != null) { 4831 mAlarmManager.cancel(mProvisioningApnAlarmIntent); 4832 mProvisioningApnAlarmIntent = null; 4833 } 4834 } 4835 4836} 4837