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