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