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