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