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