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