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