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