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