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