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