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