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