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