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