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