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