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