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