DcTracker.java revision bca51fc3a191d3ca30df627b75374db0941571c5
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.res.Resources; 30import android.database.ContentObserver; 31import android.database.Cursor; 32import android.net.ConnectivityManager; 33import android.net.LinkProperties; 34import android.net.NetworkCapabilities; 35import android.net.NetworkConfig; 36import android.net.NetworkUtils; 37import android.net.ProxyInfo; 38import android.net.Uri; 39import android.os.AsyncResult; 40import android.os.Build; 41import android.os.Bundle; 42import android.os.Handler; 43import android.os.Message; 44import android.os.RegistrantList; 45import android.os.ServiceManager; 46import android.os.SystemClock; 47import android.os.SystemProperties; 48import android.os.UserHandle; 49import android.provider.Settings; 50import android.provider.Telephony; 51import android.telephony.CellLocation; 52import android.telephony.ServiceState; 53import android.telephony.TelephonyManager; 54import android.telephony.SubscriptionManager; 55import android.telephony.cdma.CdmaCellLocation; 56import android.telephony.gsm.GsmCellLocation; 57import android.text.TextUtils; 58import android.util.EventLog; 59import android.util.LocalLog; 60import android.view.WindowManager; 61import android.telephony.Rlog; 62 63import com.android.internal.telephony.cdma.CDMALTEPhone; 64import com.android.internal.telephony.Phone; 65import com.android.internal.telephony.PhoneBase; 66import com.android.internal.telephony.DctConstants; 67import com.android.internal.telephony.EventLogTags; 68import com.android.internal.telephony.ITelephony; 69import com.android.internal.telephony.TelephonyIntents; 70import com.android.internal.telephony.gsm.GSMPhone; 71import com.android.internal.telephony.PhoneConstants; 72import com.android.internal.telephony.PhoneFactory; 73import com.android.internal.telephony.RILConstants; 74import com.android.internal.telephony.uicc.IccRecords; 75import com.android.internal.telephony.uicc.UiccController; 76import com.android.internal.util.AsyncChannel; 77import com.android.internal.util.ArrayUtils; 78 79import java.io.FileDescriptor; 80import java.io.PrintWriter; 81import java.util.ArrayList; 82import java.util.Arrays; 83import java.util.concurrent.atomic.AtomicBoolean; 84import java.util.Objects; 85import java.lang.StringBuilder; 86 87import com.android.internal.telephony.ServiceStateTracker; 88/** 89 * {@hide} 90 */ 91public final class DcTracker extends DcTrackerBase { 92 protected final String LOG_TAG = "DCT"; 93 94 /** 95 * List of messages that are waiting to be posted, when data call disconnect 96 * is complete 97 */ 98 private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>(); 99 100 private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); 101 102 protected int mDisconnectPendingCount = 0; 103 104 /** 105 * Handles changes to the APN db. 106 */ 107 private class ApnChangeObserver extends ContentObserver { 108 public ApnChangeObserver () { 109 super(mDataConnectionTracker); 110 } 111 112 @Override 113 public void onChange(boolean selfChange) { 114 sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); 115 } 116 } 117 118 //***** Instance Variables 119 120 private boolean mReregisterOnReconnectFailure = false; 121 122 123 //***** Constants 124 125 // Used by puppetmaster/*/radio_stress.py 126 private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active"; 127 128 private static final int POLL_PDP_MILLIS = 5 * 1000; 129 130 private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; 131 132 static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = 133 Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); 134 static final String APN_ID = "apn_id"; 135 136 private boolean mCanSetPreferApn = false; 137 138 private AtomicBoolean mAttached = new AtomicBoolean(false); 139 140 /** Watches for changes to the APN db. */ 141 private ApnChangeObserver mApnObserver; 142 143 private final String mProvisionActionName; 144 private BroadcastReceiver mProvisionBroadcastReceiver; 145 private ProgressDialog mProvisioningSpinner; 146 147 public boolean mImsRegistrationState = false; 148 private ApnContext mWaitCleanUpApnContext = null; 149 private boolean mDeregistrationAlarmState = false; 150 private PendingIntent mImsDeregistrationDelayIntent = null; 151 152 //***** Constructor 153 public DcTracker(PhoneBase p) { 154 super(p); 155 if (DBG) log("GsmDCT.constructor"); 156 157 mDataConnectionTracker = this; 158 update(); 159 mApnObserver = new ApnChangeObserver(); 160 p.getContext().getContentResolver().registerContentObserver( 161 Telephony.Carriers.CONTENT_URI, true, mApnObserver); 162 163 initApnContexts(); 164 165 for (ApnContext apnContext : mApnContexts.values()) { 166 // Register the reconnect and restart actions. 167 IntentFilter filter = new IntentFilter(); 168 filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); 169 filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType()); 170 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 171 } 172 173 // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases 174 initEmergencyApnSetting(); 175 addEmergencyApnSetting(); 176 177 mProvisionActionName = "com.android.internal.telephony.PROVISION" + p.getPhoneId(); 178 } 179 180 protected void registerForAllEvents() { 181 mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); 182 mPhone.mCi.registerForOffOrNotAvailable(this, 183 DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 184 mPhone.mCi.registerForDataNetworkStateChanged(this, 185 DctConstants.EVENT_DATA_STATE_CHANGED, null); 186 // Note, this is fragile - the Phone is now presenting a merged picture 187 // of PS (volte) & CS and by diving into its internals you're just seeing 188 // the CS data. This works well for the purposes this is currently used for 189 // but that may not always be the case. Should probably be redesigned to 190 // accurately reflect what we're really interested in (registerForCSVoiceCallEnded). 191 mPhone.getCallTracker().registerForVoiceCallEnded (this, 192 DctConstants.EVENT_VOICE_CALL_ENDED, null); 193 mPhone.getCallTracker().registerForVoiceCallStarted (this, 194 DctConstants.EVENT_VOICE_CALL_STARTED, null); 195 mPhone.getServiceStateTracker().registerForDataConnectionAttached(this, 196 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); 197 mPhone.getServiceStateTracker().registerForDataConnectionDetached(this, 198 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); 199 mPhone.getServiceStateTracker().registerForDataRoamingOn(this, 200 DctConstants.EVENT_ROAMING_ON, null); 201 mPhone.getServiceStateTracker().registerForDataRoamingOff(this, 202 DctConstants.EVENT_ROAMING_OFF, null); 203 mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, 204 DctConstants.EVENT_PS_RESTRICT_ENABLED, null); 205 mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, 206 DctConstants.EVENT_PS_RESTRICT_DISABLED, null); 207 // SubscriptionManager.registerForDdsSwitch(this, 208 // DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null); 209 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this, 210 DctConstants.EVENT_DATA_RAT_CHANGED, null); 211 } 212 @Override 213 public void dispose() { 214 if (DBG) log("DcTracker.dispose"); 215 216 if (mProvisionBroadcastReceiver != null) { 217 mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); 218 mProvisionBroadcastReceiver = null; 219 } 220 if (mProvisioningSpinner != null) { 221 mProvisioningSpinner.dismiss(); 222 mProvisioningSpinner = null; 223 } 224 225 cleanUpAllConnections(true, null); 226 227 super.dispose(); 228 229 mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); 230 mApnContexts.clear(); 231 mPrioritySortedApnContexts.clear(); 232 233 destroyDataConnections(); 234 } 235 protected void unregisterForAllEvents() { 236 //Unregister for all events 237 mPhone.mCi.unregisterForAvailable(this); 238 mPhone.mCi.unregisterForOffOrNotAvailable(this); 239 IccRecords r = mIccRecords.get(); 240 if (r != null) { 241 r.unregisterForRecordsLoaded(this); 242 mIccRecords.set(null); 243 } 244 mPhone.mCi.unregisterForDataNetworkStateChanged(this); 245 mPhone.getCallTracker().unregisterForVoiceCallEnded(this); 246 mPhone.getCallTracker().unregisterForVoiceCallStarted(this); 247 mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this); 248 mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this); 249 mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); 250 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 251 mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); 252 mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); 253 //SubscriptionManager.unregisterForDdsSwitch(this); 254 } 255 256 @Override 257 public void incApnRefCount(String name, LocalLog log, int serialNum) { 258 ApnContext apnContext = mApnContexts.get(name); 259 log.log("DcTracker.incApnRefCount on " + name + " found " + apnContext + " (" + 260 serialNum + ")"); 261 if (apnContext != null) { 262 apnContext.incRefCount(log, serialNum); 263 } 264 265 } 266 267 @Override 268 public void decApnRefCount(String name, LocalLog log, int serialNum) { 269 ApnContext apnContext = mApnContexts.get(name); 270 log.log("DcTracker.decApnRefCount on " + name + " found " + apnContext + " (" + 271 serialNum + ")"); 272 if (apnContext != null) { 273 apnContext.decRefCount(log, serialNum); 274 } 275 } 276 277 @Override 278 public int currentRequestCount() { 279 int total = 0; 280 for (ApnContext apnContext: mApnContexts.values()) { 281 total += apnContext.getRefCount(); 282 } 283 return total; 284 } 285 286 @Override 287 public void clearApnRefCounts() { 288 for (ApnContext apnContext : mApnContexts.values()) { 289 apnContext.clearRefCount(); 290 } 291 } 292 293 public void snapshotContexts(String logName) { 294 LocalLog l = PhoneFactory.getLocalLog(logName); 295 if (l != null) { 296 for (ApnContext apnContext : mApnContexts.values()) { 297 l.log(apnContext.toString()); 298 apnContext.copyLogTo(l); 299 } 300 } 301 } 302 303 @Override 304 public boolean isApnSupported(String name) { 305 if (name == null) { 306 loge("isApnSupported: name=null"); 307 return false; 308 } 309 ApnContext apnContext = mApnContexts.get(name); 310 if (apnContext == null) { 311 loge("Request for unsupported mobile name: " + name); 312 return false; 313 } 314 return true; 315 } 316 317 @Override 318 public int getApnPriority(String name) { 319 ApnContext apnContext = mApnContexts.get(name); 320 if (apnContext == null) { 321 loge("Request for unsupported mobile name: " + name); 322 } 323 return apnContext.priority; 324 } 325 326 // Turn telephony radio on or off. 327 private void setRadio(boolean on) { 328 final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 329 try { 330 phone.setRadio(on); 331 } catch (Exception e) { 332 // Ignore. 333 } 334 } 335 336 // Class to handle Intent dispatched with user selects the "Sign-in to network" 337 // notification. 338 private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { 339 private final String mNetworkOperator; 340 // Mobile provisioning URL. Valid while provisioning notification is up. 341 // Set prior to notification being posted as URL contains ICCID which 342 // disappears when radio is off (which is the case when notification is up). 343 private final String mProvisionUrl; 344 345 public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { 346 mNetworkOperator = networkOperator; 347 mProvisionUrl = provisionUrl; 348 } 349 350 private void setEnableFailFastMobileData(int enabled) { 351 sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); 352 } 353 354 private void enableMobileProvisioning() { 355 final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); 356 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl)); 357 sendMessage(msg); 358 } 359 360 @Override 361 public void onReceive(Context context, Intent intent) { 362 // Turning back on the radio can take time on the order of a minute, so show user a 363 // spinner so they know something is going on. 364 mProvisioningSpinner = new ProgressDialog(context); 365 mProvisioningSpinner.setTitle(mNetworkOperator); 366 mProvisioningSpinner.setMessage( 367 // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. 368 context.getText(com.android.internal.R.string.media_route_status_connecting)); 369 mProvisioningSpinner.setIndeterminate(true); 370 mProvisioningSpinner.setCancelable(true); 371 // Allow non-Activity Service Context to create a View. 372 mProvisioningSpinner.getWindow().setType( 373 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 374 mProvisioningSpinner.show(); 375 // After timeout, hide spinner so user can at least use their device. 376 // TODO: Indicate to user that it is taking an unusually long time to connect? 377 sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, 378 mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); 379 // This code is almost identical to the old 380 // ConnectivityService.handleMobileProvisioningAction code. 381 setRadio(true); 382 setEnableFailFastMobileData(DctConstants.ENABLED); 383 enableMobileProvisioning(); 384 } 385 } 386 387 @Override 388 public boolean isApnTypeActive(String type) { 389 ApnContext apnContext = mApnContexts.get(type); 390 if (apnContext == null) return false; 391 392 return (apnContext.getDcAc() != null); 393 } 394 395 @Override 396 public boolean isDataPossible(String apnType) { 397 ApnContext apnContext = mApnContexts.get(apnType); 398 if (apnContext == null) { 399 return false; 400 } 401 boolean apnContextIsEnabled = apnContext.isEnabled(); 402 DctConstants.State apnContextState = apnContext.getState(); 403 boolean apnTypePossible = !(apnContextIsEnabled && 404 (apnContextState == DctConstants.State.FAILED)); 405 boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); 406 // Set the emergency APN availability status as TRUE irrespective of conditions checked in 407 // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc. 408 boolean dataAllowed = isEmergencyApn || isDataAllowed(); 409 boolean possible = dataAllowed && apnTypePossible; 410 411 if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 412 || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA)) 413 && (mPhone.getServiceState().getRilDataRadioTechnology() 414 == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) { 415 log("Default data call activation not possible in iwlan."); 416 possible = false; 417 } 418 419 if (VDBG) { 420 log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " + 421 "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s", 422 apnType, possible, dataAllowed, apnTypePossible, 423 apnContextIsEnabled, apnContextState)); 424 } 425 return possible; 426 } 427 428 @Override 429 protected void finalize() { 430 if(DBG) log("finalize"); 431 } 432 433 private ApnContext addApnContext(String type, NetworkConfig networkConfig) { 434 ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG, networkConfig, 435 this); 436 mApnContexts.put(type, apnContext); 437 mPrioritySortedApnContexts.add(apnContext); 438 return apnContext; 439 } 440 441 protected void initApnContexts() { 442 log("initApnContexts: E"); 443 // Load device network attributes from resources 444 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray( 445 com.android.internal.R.array.networkAttributes); 446 for (String networkConfigString : networkConfigStrings) { 447 NetworkConfig networkConfig = new NetworkConfig(networkConfigString); 448 ApnContext apnContext = null; 449 450 switch (networkConfig.type) { 451 case ConnectivityManager.TYPE_MOBILE: 452 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig); 453 break; 454 case ConnectivityManager.TYPE_MOBILE_MMS: 455 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig); 456 break; 457 case ConnectivityManager.TYPE_MOBILE_SUPL: 458 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig); 459 break; 460 case ConnectivityManager.TYPE_MOBILE_DUN: 461 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig); 462 break; 463 case ConnectivityManager.TYPE_MOBILE_HIPRI: 464 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig); 465 break; 466 case ConnectivityManager.TYPE_MOBILE_FOTA: 467 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig); 468 break; 469 case ConnectivityManager.TYPE_MOBILE_IMS: 470 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig); 471 break; 472 case ConnectivityManager.TYPE_MOBILE_CBS: 473 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig); 474 break; 475 case ConnectivityManager.TYPE_MOBILE_IA: 476 apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig); 477 break; 478 case ConnectivityManager.TYPE_MOBILE_EMERGENCY: 479 apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig); 480 break; 481 default: 482 log("initApnContexts: skipping unknown type=" + networkConfig.type); 483 continue; 484 } 485 log("initApnContexts: apnContext=" + apnContext); 486 } 487 log("initApnContexts: X mApnContexts=" + mApnContexts); 488 } 489 490 @Override 491 public LinkProperties getLinkProperties(String apnType) { 492 ApnContext apnContext = mApnContexts.get(apnType); 493 if (apnContext != null) { 494 DcAsyncChannel dcac = apnContext.getDcAc(); 495 if (dcac != null) { 496 if (DBG) log("return link properites for " + apnType); 497 return dcac.getLinkPropertiesSync(); 498 } 499 } 500 if (DBG) log("return new LinkProperties"); 501 return new LinkProperties(); 502 } 503 504 @Override 505 public NetworkCapabilities getNetworkCapabilities(String apnType) { 506 ApnContext apnContext = mApnContexts.get(apnType); 507 if (apnContext!=null) { 508 DcAsyncChannel dataConnectionAc = apnContext.getDcAc(); 509 if (dataConnectionAc != null) { 510 if (DBG) { 511 log("get active pdp is not null, return NetworkCapabilities for " + apnType); 512 } 513 return dataConnectionAc.getNetworkCapabilitiesSync(); 514 } 515 } 516 if (DBG) log("return new NetworkCapabilities"); 517 return new NetworkCapabilities(); 518 } 519 520 @Override 521 // Return all active apn types 522 public String[] getActiveApnTypes() { 523 if (DBG) log("get all active apn types"); 524 ArrayList<String> result = new ArrayList<String>(); 525 526 for (ApnContext apnContext : mApnContexts.values()) { 527 if (mAttached.get() && apnContext.isReady()) { 528 result.add(apnContext.getApnType()); 529 } 530 } 531 532 return result.toArray(new String[0]); 533 } 534 535 @Override 536 // Return active apn of specific apn type 537 public String getActiveApnString(String apnType) { 538 if (VDBG) log( "get active apn string for type:" + apnType); 539 ApnContext apnContext = mApnContexts.get(apnType); 540 if (apnContext != null) { 541 ApnSetting apnSetting = apnContext.getApnSetting(); 542 if (apnSetting != null) { 543 return apnSetting.apn; 544 } 545 } 546 return null; 547 } 548 549 @Override 550 public boolean isApnTypeEnabled(String apnType) { 551 ApnContext apnContext = mApnContexts.get(apnType); 552 if (apnContext == null) { 553 return false; 554 } 555 return apnContext.isEnabled(); 556 } 557 558 @Override 559 protected void setState(DctConstants.State s) { 560 if (DBG) log("setState should not be used in GSM" + s); 561 } 562 563 // Return state of specific apn type 564 @Override 565 public DctConstants.State getState(String apnType) { 566 ApnContext apnContext = mApnContexts.get(apnType); 567 if (apnContext != null) { 568 return apnContext.getState(); 569 } 570 return DctConstants.State.FAILED; 571 } 572 573 // Return if apn type is a provisioning apn. 574 @Override 575 protected boolean isProvisioningApn(String apnType) { 576 ApnContext apnContext = mApnContexts.get(apnType); 577 if (apnContext != null) { 578 return apnContext.isProvisioningApn(); 579 } 580 return false; 581 } 582 583 // Return state of overall 584 @Override 585 public DctConstants.State getOverallState() { 586 boolean isConnecting = false; 587 boolean isFailed = true; // All enabled Apns should be FAILED. 588 boolean isAnyEnabled = false; 589 590 for (ApnContext apnContext : mApnContexts.values()) { 591 if (apnContext.isEnabled()) { 592 isAnyEnabled = true; 593 switch (apnContext.getState()) { 594 case CONNECTED: 595 case DISCONNECTING: 596 if (DBG) log("overall state is CONNECTED"); 597 return DctConstants.State.CONNECTED; 598 case RETRYING: 599 case CONNECTING: 600 isConnecting = true; 601 isFailed = false; 602 break; 603 case IDLE: 604 case SCANNING: 605 isFailed = false; 606 break; 607 default: 608 isAnyEnabled = true; 609 break; 610 } 611 } 612 } 613 614 if (!isAnyEnabled) { // Nothing enabled. return IDLE. 615 if (DBG) log( "overall state is IDLE"); 616 return DctConstants.State.IDLE; 617 } 618 619 if (isConnecting) { 620 if (DBG) log( "overall state is CONNECTING"); 621 return DctConstants.State.CONNECTING; 622 } else if (!isFailed) { 623 if (DBG) log( "overall state is IDLE"); 624 return DctConstants.State.IDLE; 625 } else { 626 if (DBG) log( "overall state is FAILED"); 627 return DctConstants.State.FAILED; 628 } 629 } 630 631 @Override 632 protected boolean isApnTypeAvailable(String type) { 633 if (type.equals(PhoneConstants.APN_TYPE_DUN) && fetchDunApn() != null) { 634 return true; 635 } 636 637 if (mAllApnSettings != null) { 638 for (ApnSetting apn : mAllApnSettings) { 639 if (apn.canHandleType(type)) { 640 return true; 641 } 642 } 643 } 644 return false; 645 } 646 647 /** 648 * Report on whether data connectivity is enabled for any APN. 649 * @return {@code false} if data connectivity has been explicitly disabled, 650 * {@code true} otherwise. 651 */ 652 @Override 653 public boolean getAnyDataEnabled() { 654 synchronized (mDataEnabledLock) { 655 if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false; 656 for (ApnContext apnContext : mApnContexts.values()) { 657 // Make sure we don't have a context that is going down 658 // and is explicitly disabled. 659 if (isDataAllowed(apnContext)) { 660 return true; 661 } 662 } 663 return false; 664 } 665 } 666 667 public boolean getAnyDataEnabled(boolean checkUserDataEnabled) { 668 synchronized (mDataEnabledLock) { 669 if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled) 670 && (!checkUserDataEnabled || sPolicyDataEnabled))) 671 return false; 672 673 for (ApnContext apnContext : mApnContexts.values()) { 674 // Make sure we dont have a context that going down 675 // and is explicitly disabled. 676 if (isDataAllowed(apnContext)) { 677 return true; 678 } 679 } 680 return false; 681 } 682 } 683 684 private boolean isDataAllowed(ApnContext apnContext) { 685 //If RAT is iwlan then dont allow default/IA PDP at all. 686 //Rest of APN types can be evaluated for remaining conditions. 687 if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 688 || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA)) 689 && (mPhone.getServiceState().getRilDataRadioTechnology() 690 == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) { 691 log("Default data call activation not allowed in iwlan."); 692 return false; 693 } else { 694 return apnContext.isReady() && isDataAllowed(); 695 } 696 } 697 698 //****** Called from ServiceStateTracker 699 /** 700 * Invoked when ServiceStateTracker observes a transition from GPRS 701 * attach to detach. 702 */ 703 protected void onDataConnectionDetached() { 704 /* 705 * We presently believe it is unnecessary to tear down the PDP context 706 * when GPRS detaches, but we should stop the network polling. 707 */ 708 if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); 709 stopNetStatPoll(); 710 stopDataStallAlarm(); 711 notifyDataConnection(Phone.REASON_DATA_DETACHED); 712 mAttached.set(false); 713 } 714 715 private void onDataConnectionAttached() { 716 if (DBG) log("onDataConnectionAttached"); 717 mAttached.set(true); 718 if (getOverallState() == DctConstants.State.CONNECTED) { 719 if (DBG) log("onDataConnectionAttached: start polling notify attached"); 720 startNetStatPoll(); 721 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 722 notifyDataConnection(Phone.REASON_DATA_ATTACHED); 723 } else { 724 // update APN availability so that APN can be enabled. 725 notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED); 726 } 727 if (mAutoAttachOnCreationConfig) { 728 mAutoAttachOnCreation = true; 729 } 730 setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED); 731 } 732 733 @Override 734 protected boolean isDataAllowed() { 735 final boolean internalDataEnabled; 736 synchronized (mDataEnabledLock) { 737 internalDataEnabled = mInternalDataEnabled; 738 } 739 740 boolean attachedState = mAttached.get(); 741 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); 742 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 743 if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { 744 desiredPowerState = true; 745 } 746 747 IccRecords r = mIccRecords.get(); 748 boolean recordsLoaded = false; 749 if (r != null) { 750 recordsLoaded = r.getRecordsLoaded(); 751 if (DBG && !recordsLoaded) log("isDataAllowed getRecordsLoaded=" + recordsLoaded); 752 } 753 754 //FIXME always attach 755 boolean psRestricted = mIsPsRestricted; 756 int phoneNum = TelephonyManager.getDefault().getPhoneCount(); 757 if (phoneNum > 1) { 758 attachedState = true; 759 psRestricted = false; 760 } 761 int dataSub = SubscriptionManager.getDefaultDataSubId(); 762 boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub); 763 PhoneConstants.State state = PhoneConstants.State.IDLE; 764 // Note this is explicitly not using mPhone.getState. See b/19090488. 765 // mPhone.getState reports the merge of CS and PS (volte) voice call state 766 // but we only care about CS calls here for data/voice concurrency issues. 767 // Calling getCallTracker currently gives you just the CS side where the 768 // ImsCallTracker is held internally where applicable. 769 // This should be redesigned to ask explicitly what we want: 770 // voiceCallStateAllowDataCall, or dataCallAllowed or something similar. 771 if (mPhone.getCallTracker() != null) { 772 state = mPhone.getCallTracker().getState(); 773 } 774 boolean allowed = 775 (attachedState || mAutoAttachOnCreation) && 776 recordsLoaded && 777 (state == PhoneConstants.State.IDLE || 778 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) && 779 internalDataEnabled && 780 defaultDataSelected && 781 (!mPhone.getServiceState().getDataRoaming() || getDataOnRoamingEnabled()) && 782 //!mIsPsRestricted && 783 !psRestricted && 784 desiredPowerState; 785 if (!allowed && DBG) { 786 String reason = ""; 787 if (!(attachedState || mAutoAttachOnCreation)) { 788 reason += " - Attached= " + attachedState; 789 } 790 if (!recordsLoaded) reason += " - SIM not loaded"; 791 if (state != PhoneConstants.State.IDLE && 792 !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 793 reason += " - PhoneState= " + state; 794 reason += " - Concurrent voice and data not allowed"; 795 } 796 if (!internalDataEnabled) reason += " - mInternalDataEnabled= false"; 797 if (!defaultDataSelected) reason += " - defaultDataSelected= false"; 798 if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) { 799 reason += " - Roaming and data roaming not enabled"; 800 } 801 if (mIsPsRestricted) reason += " - mIsPsRestricted= true"; 802 if (!desiredPowerState) reason += " - desiredPowerState= false"; 803 if (DBG) log("isDataAllowed: not allowed due to" + reason); 804 } 805 return allowed; 806 } 807 808 // arg for setupDataOnConnectableApns 809 private enum RetryFailures { 810 // retry failed networks always (the old default) 811 ALWAYS, 812 // retry only when a substantial change has occured. Either: 813 // 1) we were restricted by voice/data concurrency and aren't anymore 814 // 2) our apn list has change 815 ONLY_ON_CHANGE 816 }; 817 818 private void setupDataOnConnectableApns(String reason) { 819 setupDataOnConnectableApns(reason, RetryFailures.ALWAYS); 820 } 821 822 private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) { 823 if (DBG) log("setupDataOnConnectableApns: " + reason); 824 825 for (ApnContext apnContext : mPrioritySortedApnContexts) { 826 ArrayList<ApnSetting> waitingApns = null; 827 828 if (DBG) log("setupDataOnConnectableApns: apnContext " + apnContext); 829 if (apnContext.getState() == DctConstants.State.FAILED 830 || apnContext.getState() == DctConstants.State.RETRYING) { 831 if (retryFailures == RetryFailures.ALWAYS) { 832 apnContext.setState(DctConstants.State.IDLE); 833 } else if (apnContext.isConcurrentVoiceAndDataAllowed() == false && 834 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 835 // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed 836 apnContext.setState(DctConstants.State.IDLE); 837 } else { 838 // RetryFailures.ONLY_ON_CHANGE - check if the apns have changed 839 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 840 ArrayList<ApnSetting> originalApns = apnContext.getOriginalWaitingApns(); 841 if (originalApns != null && originalApns.isEmpty() == false) { 842 waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech); 843 if (originalApns.size() != waitingApns.size() || 844 originalApns.containsAll(waitingApns) == false) { 845 apnContext.setState(DctConstants.State.IDLE); 846 } 847 } 848 } 849 } 850 if (apnContext.isConnectable()) { 851 log("setupDataOnConnectableApns: isConnectable() call trySetupData"); 852 apnContext.setReason(reason); 853 trySetupData(apnContext, waitingApns); 854 } 855 } 856 } 857 858 private boolean trySetupData(ApnContext apnContext) { 859 return trySetupData(apnContext, null); 860 } 861 862 private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) { 863 if (DBG) { 864 log("trySetupData for type:" + apnContext.getApnType() + 865 " due to " + apnContext.getReason() + " apnContext=" + apnContext); 866 log("trySetupData with mIsPsRestricted=" + mIsPsRestricted); 867 } 868 apnContext.requestLog("trySetupData due to " + apnContext.getReason()); 869 870 if (mPhone.getSimulatedRadioControl() != null) { 871 // Assume data is connected on the simulator 872 // FIXME this can be improved 873 apnContext.setState(DctConstants.State.CONNECTED); 874 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 875 876 log("trySetupData: X We're on the simulator; assuming connected retValue=true"); 877 return true; 878 } 879 880 // Allow SETUP_DATA request for E-APN to be completed during emergency call 881 // and MOBILE DATA On/Off cases as well. 882 boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); 883 final ServiceStateTracker sst = mPhone.getServiceStateTracker(); 884 boolean desiredPowerState = sst.getDesiredPowerState(); 885 boolean checkUserDataEnabled = 886 !(apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)); 887 888 if (apnContext.isConnectable() && (isEmergencyApn || 889 (isDataAllowed(apnContext) && 890 getAnyDataEnabled(checkUserDataEnabled) && !isEmergency()))) { 891 if (apnContext.getState() == DctConstants.State.FAILED) { 892 String str ="trySetupData: make a FAILED ApnContext IDLE so its reusable"; 893 if (DBG) log(str); 894 apnContext.requestLog(str); 895 apnContext.setState(DctConstants.State.IDLE); 896 } 897 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 898 apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed()); 899 if (apnContext.getState() == DctConstants.State.IDLE) { 900 if (waitingApns == null) { 901 waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech); 902 } 903 if (waitingApns.isEmpty()) { 904 notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext); 905 notifyOffApnsOfAvailability(apnContext.getReason()); 906 String str = "trySetupData: X No APN found retValue=false"; 907 if (DBG) log(str); 908 apnContext.requestLog(str); 909 return false; 910 } else { 911 apnContext.setWaitingApns(waitingApns); 912 if (DBG) { 913 log ("trySetupData: Create from mAllApnSettings : " 914 + apnListToString(mAllApnSettings)); 915 } 916 } 917 } 918 919 if (DBG) { 920 log("trySetupData: call setupData, waitingApns : " 921 + apnListToString(apnContext.getWaitingApns())); 922 } 923 boolean retValue = setupData(apnContext, radioTech); 924 notifyOffApnsOfAvailability(apnContext.getReason()); 925 926 if (DBG) log("trySetupData: X retValue=" + retValue); 927 return retValue; 928 } else { 929 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 930 && apnContext.isConnectable()) { 931 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 932 } 933 notifyOffApnsOfAvailability(apnContext.getReason()); 934 String str = "trySetupData: X apnContext not 'ready' retValue=false"; 935 apnContext.requestLog(str); 936 if (DBG) { 937 log(str); 938 if (!apnContext.isConnectable()) log("apnContext.isConnectable = false"); 939 if (!isDataAllowed(apnContext)) log("isDataAllowed = false"); 940 if (!getAnyDataEnabled(checkUserDataEnabled)) { 941 log("getAnyDataEnabled(" + checkUserDataEnabled + ") = false"); 942 } 943 } 944 return false; 945 } 946 } 947 948 @Override 949 // Disabled apn's still need avail/unavail notificiations - send them out 950 protected void notifyOffApnsOfAvailability(String reason) { 951 for (ApnContext apnContext : mApnContexts.values()) { 952 if (!mAttached.get() || !apnContext.isReady()) { 953 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType()); 954 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 955 apnContext.getApnType(), 956 PhoneConstants.DataState.DISCONNECTED); 957 } else { 958 if (VDBG) { 959 log("notifyOffApnsOfAvailability skipped apn due to attached && isReady " + 960 apnContext.toString()); 961 } 962 } 963 } 964 } 965 966 /** 967 * If tearDown is true, this only tears down a CONNECTED session. Presently, 968 * there is no mechanism for abandoning an CONNECTING session, 969 * but would likely involve cancelling pending async requests or 970 * setting a flag or new state to ignore them when they came in 971 * @param tearDown true if the underlying DataConnection should be 972 * disconnected. 973 * @param reason reason for the clean up. 974 * @return boolean - true if we did cleanup any connections, false if they 975 * were already all disconnected. 976 */ 977 protected boolean cleanUpAllConnections(boolean tearDown, String reason) { 978 if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason); 979 boolean didDisconnect = false; 980 boolean specificdisable = false; 981 982 if (!TextUtils.isEmpty(reason)) { 983 specificdisable = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED); 984 } 985 986 for (ApnContext apnContext : mApnContexts.values()) { 987 if (apnContext.isDisconnected() == false) didDisconnect = true; 988 if (specificdisable) { 989 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)) { 990 if (DBG) log("ApnConextType: " + apnContext.getApnType()); 991 apnContext.setReason(reason); 992 cleanUpConnection(tearDown, apnContext); 993 } 994 } else { 995 // TODO - only do cleanup if not disconnected 996 apnContext.setReason(reason); 997 cleanUpConnection(tearDown, apnContext); 998 } 999 } 1000 1001 stopNetStatPoll(); 1002 stopDataStallAlarm(); 1003 1004 // TODO: Do we need mRequestedApnType? 1005 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 1006 1007 log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount); 1008 if (tearDown && mDisconnectPendingCount == 0) { 1009 notifyDataDisconnectComplete(); 1010 notifyAllDataDisconnected(); 1011 } 1012 1013 return didDisconnect; 1014 } 1015 1016 /** 1017 * Cleanup all connections. 1018 * 1019 * TODO: Cleanup only a specified connection passed as a parameter. 1020 * Also, make sure when you clean up a conn, if it is last apply 1021 * logic as though it is cleanupAllConnections 1022 * 1023 * @param cause for the clean up. 1024 */ 1025 1026 @Override 1027 protected void onCleanUpAllConnections(String cause) { 1028 cleanUpAllConnections(true, cause); 1029 } 1030 1031 protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) { 1032 1033 if (apnContext == null) { 1034 if (DBG) log("cleanUpConnection: apn context is null"); 1035 return; 1036 } 1037 1038 DcAsyncChannel dcac = apnContext.getDcAc(); 1039 String str = "cleanUpConnection: tearDown=" + tearDown + " reason=" + 1040 apnContext.getReason(); 1041 if (DBG) log(str + " apnContext=" + apnContext); 1042 apnContext.requestLog(str); 1043 if (tearDown) { 1044 if (apnContext.isDisconnected()) { 1045 // The request is tearDown and but ApnContext is not connected. 1046 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. 1047 apnContext.setState(DctConstants.State.IDLE); 1048 if (!apnContext.isReady()) { 1049 if (dcac != null) { 1050 str = "cleanUpConnection: teardown, disconnectd, !ready"; 1051 if (DBG) log(str + " apnContext=" + apnContext); 1052 apnContext.requestLog(str); 1053 dcac.tearDown(apnContext, "", null); 1054 } 1055 apnContext.setDataConnectionAc(null); 1056 } 1057 } else { 1058 // Connection is still there. Try to clean up. 1059 if (dcac != null) { 1060 if (apnContext.getState() != DctConstants.State.DISCONNECTING) { 1061 boolean disconnectAll = false; 1062 if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) { 1063 // CAF_MSIM is this below condition required. 1064 // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) { 1065 if (teardownForDun()) { 1066 if (DBG) { 1067 log("cleanUpConnection: disconnectAll DUN connection"); 1068 } 1069 // we need to tear it down - we brought it up just for dun and 1070 // other people are camped on it and now dun is done. We need 1071 // to stop using it and let the normal apn list get used to find 1072 // connections for the remaining desired connections 1073 disconnectAll = true; 1074 } 1075 } 1076 str = "cleanUpConnection: tearing down" + (disconnectAll ? " all" : ""); 1077 if (DBG) log(str + "apnContext=" + apnContext); 1078 apnContext.requestLog(str); 1079 Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext); 1080 if (disconnectAll) { 1081 apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg); 1082 } else { 1083 apnContext.getDcAc() 1084 .tearDown(apnContext, apnContext.getReason(), msg); 1085 } 1086 apnContext.setState(DctConstants.State.DISCONNECTING); 1087 mDisconnectPendingCount++; 1088 } 1089 } else { 1090 // apn is connected but no reference to dcac. 1091 // Should not be happen, but reset the state in case. 1092 apnContext.setState(DctConstants.State.IDLE); 1093 apnContext.requestLog("cleanUpConnection: connected, bug no DCAC"); 1094 mPhone.notifyDataConnection(apnContext.getReason(), 1095 apnContext.getApnType()); 1096 } 1097 } 1098 } else { 1099 // force clean up the data connection. 1100 if (dcac != null) dcac.reqReset(); 1101 apnContext.setState(DctConstants.State.IDLE); 1102 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1103 apnContext.setDataConnectionAc(null); 1104 } 1105 1106 // Make sure reconnection alarm is cleaned up if there is no ApnContext 1107 // associated to the connection. 1108 if (dcac != null) { 1109 cancelReconnectAlarm(apnContext); 1110 } 1111 str = "cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason(); 1112 if (DBG) log(str + " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc()); 1113 apnContext.requestLog(str); 1114 } 1115 1116 /** 1117 * Determine if DUN connection is special and we need to teardown on start/stop 1118 */ 1119 private boolean teardownForDun() { 1120 // CDMA always needs to do this the profile id is correct 1121 final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology(); 1122 if (ServiceState.isCdma(rilRat)) return true; 1123 1124 return (fetchDunApn() != null); 1125 } 1126 1127 /** 1128 * Cancels the alarm associated with apnContext. 1129 * 1130 * @param apnContext on which the alarm should be stopped. 1131 */ 1132 private void cancelReconnectAlarm(ApnContext apnContext) { 1133 if (apnContext == null) return; 1134 1135 PendingIntent intent = apnContext.getReconnectIntent(); 1136 1137 if (intent != null) { 1138 AlarmManager am = 1139 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1140 am.cancel(intent); 1141 apnContext.setReconnectIntent(null); 1142 } 1143 } 1144 1145 /** 1146 * @param types comma delimited list of APN types 1147 * @return array of APN types 1148 */ 1149 private String[] parseTypes(String types) { 1150 String[] result; 1151 // If unset, set to DEFAULT. 1152 if (types == null || types.equals("")) { 1153 result = new String[1]; 1154 result[0] = PhoneConstants.APN_TYPE_ALL; 1155 } else { 1156 result = types.split(","); 1157 } 1158 return result; 1159 } 1160 1161 @Override 1162 protected boolean isPermanentFail(DcFailCause dcFailCause) { 1163 return (dcFailCause.isPermanentFail() && 1164 (mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST)); 1165 } 1166 1167 private ApnSetting makeApnSetting(Cursor cursor) { 1168 String[] types = parseTypes( 1169 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); 1170 ApnSetting apn = new ApnSetting( 1171 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), 1172 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), 1173 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), 1174 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), 1175 NetworkUtils.trimV4AddrZeros( 1176 cursor.getString( 1177 cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), 1178 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), 1179 NetworkUtils.trimV4AddrZeros( 1180 cursor.getString( 1181 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), 1182 NetworkUtils.trimV4AddrZeros( 1183 cursor.getString( 1184 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), 1185 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), 1186 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), 1187 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), 1188 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), 1189 types, 1190 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), 1191 cursor.getString(cursor.getColumnIndexOrThrow( 1192 Telephony.Carriers.ROAMING_PROTOCOL)), 1193 cursor.getInt(cursor.getColumnIndexOrThrow( 1194 Telephony.Carriers.CARRIER_ENABLED)) == 1, 1195 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)), 1196 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER_BITMASK)), 1197 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), 1198 cursor.getInt(cursor.getColumnIndexOrThrow( 1199 Telephony.Carriers.MODEM_COGNITIVE)) == 1, 1200 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), 1201 cursor.getInt(cursor.getColumnIndexOrThrow( 1202 Telephony.Carriers.WAIT_TIME)), 1203 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)), 1204 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), 1205 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE)), 1206 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA))); 1207 return apn; 1208 } 1209 1210 private ArrayList<ApnSetting> createApnList(Cursor cursor) { 1211 ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>(); 1212 ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>(); 1213 IccRecords r = mIccRecords.get(); 1214 1215 if (cursor.moveToFirst()) { 1216 do { 1217 ApnSetting apn = makeApnSetting(cursor); 1218 if (apn == null) { 1219 continue; 1220 } 1221 1222 if (apn.hasMvnoParams()) { 1223 if (r != null && ApnSetting.mvnoMatches(r, apn.mvnoType, apn.mvnoMatchData)) { 1224 mvnoApns.add(apn); 1225 } 1226 } else { 1227 mnoApns.add(apn); 1228 } 1229 } while (cursor.moveToNext()); 1230 } 1231 1232 ArrayList<ApnSetting> result = mvnoApns.isEmpty() ? mnoApns : mvnoApns; 1233 if (DBG) log("createApnList: X result=" + result); 1234 return result; 1235 } 1236 1237 private boolean dataConnectionNotInUse(DcAsyncChannel dcac) { 1238 if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac); 1239 for (ApnContext apnContext : mApnContexts.values()) { 1240 if (apnContext.getDcAc() == dcac) { 1241 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext); 1242 return false; 1243 } 1244 } 1245 // TODO: Fix retry handling so free DataConnections have empty apnlists. 1246 // Probably move retry handling into DataConnections and reduce complexity 1247 // of DCT. 1248 if (DBG) log("dataConnectionNotInUse: tearDownAll"); 1249 dcac.tearDownAll("No connection", null); 1250 if (DBG) log("dataConnectionNotInUse: not in use return true"); 1251 return true; 1252 } 1253 1254 private DcAsyncChannel findFreeDataConnection() { 1255 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 1256 if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) { 1257 if (DBG) { 1258 log("findFreeDataConnection: found free DataConnection=" + 1259 " dcac=" + dcac); 1260 } 1261 return dcac; 1262 } 1263 } 1264 log("findFreeDataConnection: NO free DataConnection"); 1265 return null; 1266 } 1267 1268 private boolean setupData(ApnContext apnContext, int radioTech) { 1269 if (DBG) log("setupData: apnContext=" + apnContext); 1270 apnContext.requestLog("setupData"); 1271 ApnSetting apnSetting; 1272 DcAsyncChannel dcac = null; 1273 1274 apnSetting = apnContext.getNextWaitingApn(); 1275 if (apnSetting == null) { 1276 if (DBG) log("setupData: return for no apn found!"); 1277 return false; 1278 } 1279 1280 int profileId = apnSetting.profileId; 1281 if (profileId == 0) { 1282 profileId = getApnProfileID(apnContext.getApnType()); 1283 } 1284 1285 // On CDMA, if we're explicitly asking for DUN, we need have 1286 // a dun-profiled connection so we can't share an existing one 1287 // On GSM/LTE we can share existing apn connections provided they support 1288 // this type. 1289 if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN || 1290 teardownForDun() == false) { 1291 dcac = checkForCompatibleConnectedApnContext(apnContext); 1292 if (dcac != null) { 1293 // Get the dcacApnSetting for the connection we want to share. 1294 ApnSetting dcacApnSetting = dcac.getApnSettingSync(); 1295 if (dcacApnSetting != null) { 1296 // Setting is good, so use it. 1297 apnSetting = dcacApnSetting; 1298 } 1299 } 1300 } 1301 if (dcac == null) { 1302 if (isOnlySingleDcAllowed(radioTech)) { 1303 if (isHigherPriorityApnContextActive(apnContext)) { 1304 if (DBG) { 1305 log("setupData: Higher priority ApnContext active. Ignoring call"); 1306 } 1307 return false; 1308 } 1309 1310 // Only lower priority calls left. Disconnect them all in this single PDP case 1311 // so that we can bring up the requested higher priority call (once we receive 1312 // repsonse for deactivate request for the calls we are about to disconnect 1313 if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { 1314 // If any call actually requested to be disconnected, means we can't 1315 // bring up this connection yet as we need to wait for those data calls 1316 // to be disconnected. 1317 if (DBG) log("setupData: Some calls are disconnecting first. Wait and retry"); 1318 return false; 1319 } 1320 1321 // No other calls are active, so proceed 1322 if (DBG) log("setupData: Single pdp. Continue setting up data call."); 1323 } 1324 1325 dcac = findFreeDataConnection(); 1326 1327 if (dcac == null) { 1328 dcac = createDataConnection(); 1329 } 1330 1331 if (dcac == null) { 1332 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); 1333 return false; 1334 } 1335 } 1336 if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting); 1337 1338 apnContext.setDataConnectionAc(dcac); 1339 apnContext.setApnSetting(apnSetting); 1340 apnContext.setState(DctConstants.State.CONNECTING); 1341 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1342 1343 Message msg = obtainMessage(); 1344 msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; 1345 msg.obj = apnContext; 1346 dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation, 1347 msg); 1348 1349 if (DBG) log("setupData: initing!"); 1350 return true; 1351 } 1352 1353 /** 1354 * Handles changes to the APN database. 1355 */ 1356 private void onApnChanged() { 1357 DctConstants.State overallState = getOverallState(); 1358 boolean isDisconnected = (overallState == DctConstants.State.IDLE || 1359 overallState == DctConstants.State.FAILED); 1360 1361 if (mPhone instanceof GSMPhone) { 1362 // The "current" may no longer be valid. MMS depends on this to send properly. TBD 1363 ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); 1364 } 1365 1366 // TODO: It'd be nice to only do this if the changed entrie(s) 1367 // match the current operator. 1368 if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); 1369 createAllApnList(); 1370 setInitialAttachApn(); 1371 cleanUpConnectionsOnUpdatedApns(!isDisconnected); 1372 1373 // FIXME: See bug 17426028 maybe no conditional is needed. 1374 if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId()) { 1375 setupDataOnConnectableApns(Phone.REASON_APN_CHANGED); 1376 } 1377 } 1378 1379 /** 1380 * @param cid Connection id provided from RIL. 1381 * @return DataConnectionAc associated with specified cid. 1382 */ 1383 private DcAsyncChannel findDataConnectionAcByCid(int cid) { 1384 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 1385 if (dcac.getCidSync() == cid) { 1386 return dcac; 1387 } 1388 } 1389 return null; 1390 } 1391 1392 // TODO: For multiple Active APNs not exactly sure how to do this. 1393 @Override 1394 protected void gotoIdleAndNotifyDataConnection(String reason) { 1395 if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); 1396 notifyDataConnection(reason); 1397 mActiveApn = null; 1398 } 1399 1400 /** 1401 * "Active" here means ApnContext isEnabled() and not in FAILED state 1402 * @param apnContext to compare with 1403 * @return true if higher priority active apn found 1404 */ 1405 private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { 1406 for (ApnContext otherContext : mPrioritySortedApnContexts) { 1407 if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; 1408 if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { 1409 return true; 1410 } 1411 } 1412 return false; 1413 } 1414 1415 /** 1416 * Reports if we support multiple connections or not. 1417 * This is a combination of factors, based on carrier and RAT. 1418 * @param rilRadioTech the RIL Radio Tech currently in use 1419 * @return true if only single DataConnection is allowed 1420 */ 1421 private boolean isOnlySingleDcAllowed(int rilRadioTech) { 1422 int[] singleDcRats = mPhone.getContext().getResources().getIntArray( 1423 com.android.internal.R.array.config_onlySingleDcAllowed); 1424 boolean onlySingleDcAllowed = false; 1425 if (Build.IS_DEBUGGABLE && 1426 SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { 1427 onlySingleDcAllowed = true; 1428 } 1429 if (singleDcRats != null) { 1430 for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) { 1431 if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true; 1432 } 1433 } 1434 1435 if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed); 1436 return onlySingleDcAllowed; 1437 } 1438 1439 @Override 1440 protected void restartRadio() { 1441 if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); 1442 cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF); 1443 mPhone.getServiceStateTracker().powerOffRadioSafely(this); 1444 /* Note: no need to call setRadioPower(true). Assuming the desired 1445 * radio power state is still ON (as tracked by ServiceStateTracker), 1446 * ServiceStateTracker will call setRadioPower when it receives the 1447 * RADIO_STATE_CHANGED notification for the power off. And if the 1448 * desired power state has changed in the interim, we don't want to 1449 * override it with an unconditional power on. 1450 */ 1451 1452 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0")); 1453 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); 1454 } 1455 1456 /** 1457 * Return true if data connection need to be setup after disconnected due to 1458 * reason. 1459 * 1460 * @param reason the reason why data is disconnected 1461 * @return true if try setup data connection is need for this reason 1462 */ 1463 private boolean retryAfterDisconnected(ApnContext apnContext) { 1464 boolean retry = true; 1465 String reason = apnContext.getReason(); 1466 1467 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || 1468 (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) 1469 && isHigherPriorityApnContextActive(apnContext))) { 1470 retry = false; 1471 } 1472 return retry; 1473 } 1474 1475 private void startAlarmForReconnect(int delay, ApnContext apnContext) { 1476 String apnType = apnContext.getApnType(); 1477 1478 Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType); 1479 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); 1480 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType); 1481 1482 // Get current sub id. 1483 int subId = SubscriptionManager.getDefaultDataSubId(); 1484 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1485 1486 if (DBG) { 1487 log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction() 1488 + " apn=" + apnContext); 1489 } 1490 1491 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, 1492 intent, PendingIntent.FLAG_UPDATE_CURRENT); 1493 apnContext.setReconnectIntent(alarmIntent); 1494 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1495 SystemClock.elapsedRealtime() + delay, alarmIntent); 1496 } 1497 1498 private void startAlarmForRestartTrySetup(int delay, ApnContext apnContext) { 1499 String apnType = apnContext.getApnType(); 1500 Intent intent = new Intent(INTENT_RESTART_TRYSETUP_ALARM + "." + apnType); 1501 intent.putExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE, apnType); 1502 1503 if (DBG) { 1504 log("startAlarmForRestartTrySetup: delay=" + delay + " action=" + intent.getAction() 1505 + " apn=" + apnContext); 1506 } 1507 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, 1508 intent, PendingIntent.FLAG_UPDATE_CURRENT); 1509 apnContext.setReconnectIntent(alarmIntent); 1510 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1511 SystemClock.elapsedRealtime() + delay, alarmIntent); 1512 } 1513 1514 private void notifyNoData(DcFailCause lastFailCauseCode, 1515 ApnContext apnContext) { 1516 if (DBG) log( "notifyNoData: type=" + apnContext.getApnType()); 1517 if (isPermanentFail(lastFailCauseCode) 1518 && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) { 1519 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 1520 } 1521 } 1522 1523 private void onRecordsLoaded() { 1524 if (DBG) log("onRecordsLoaded: createAllApnList"); 1525 mAutoAttachOnCreationConfig = mPhone.getContext().getResources() 1526 .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); 1527 1528 createAllApnList(); 1529 setInitialAttachApn(); 1530 if (mPhone.mCi.getRadioState().isOn()) { 1531 if (DBG) log("onRecordsLoaded: notifying data availability"); 1532 notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); 1533 } 1534 setupDataOnConnectableApns(Phone.REASON_SIM_LOADED); 1535 } 1536 1537 private void onSimNotReady() { 1538 if (DBG) log("onSimNotReady"); 1539 1540 cleanUpAllConnections(true, Phone.REASON_SIM_NOT_READY); 1541 mAllApnSettings = null; 1542 mAutoAttachOnCreationConfig = false; 1543 } 1544 1545 @Override 1546 protected void onSetDependencyMet(String apnType, boolean met) { 1547 // don't allow users to tweak hipri to work around default dependency not met 1548 if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return; 1549 1550 ApnContext apnContext = mApnContexts.get(apnType); 1551 if (apnContext == null) { 1552 loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" + 1553 apnType + ", " + met + ")"); 1554 return; 1555 } 1556 applyNewState(apnContext, apnContext.isEnabled(), met); 1557 if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) { 1558 // tie actions on default to similar actions on HIPRI regarding dependencyMet 1559 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI); 1560 if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met); 1561 } 1562 } 1563 1564 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) { 1565 boolean cleanup = false; 1566 boolean trySetup = false; 1567 String str ="applyNewState(" + apnContext.getApnType() + ", " + enabled + 1568 "(" + apnContext.isEnabled() + "), " + met + "(" + 1569 apnContext.getDependencyMet() +"))"; 1570 if (DBG) log(str); 1571 apnContext.requestLog(str); 1572 1573 if (apnContext.isReady()) { 1574 cleanup = true; 1575 if (enabled && met) { 1576 DctConstants.State state = apnContext.getState(); 1577 switch(state) { 1578 case CONNECTING: 1579 case SCANNING: 1580 case CONNECTED: 1581 case DISCONNECTING: 1582 // We're "READY" and active so just return 1583 if (DBG) log("applyNewState: 'ready' so return"); 1584 apnContext.requestLog("applyNewState state=" + state + ", so return"); 1585 return; 1586 case IDLE: 1587 // fall through: this is unexpected but if it happens cleanup and try setup 1588 case FAILED: 1589 case RETRYING: { 1590 // We're "READY" but not active so disconnect (cleanup = true) and 1591 // connect (trySetup = true) to be sure we retry the connection. 1592 trySetup = true; 1593 apnContext.setReason(Phone.REASON_DATA_ENABLED); 1594 break; 1595 } 1596 } 1597 } else if (met) { 1598 apnContext.setReason(Phone.REASON_DATA_DISABLED); 1599 // If ConnectivityService has disabled this network, stop trying to bring 1600 // it up, but do not tear it down - ConnectivityService will do that 1601 // directly by talking with the DataConnection. 1602 // 1603 // This doesn't apply to DUN, however. Those connections have special 1604 // requirements from carriers and we need stop using them when the dun 1605 // request goes away. This applies to both CDMA and GSM because they both 1606 // can declare the DUN APN sharable by default traffic, thus still satisfying 1607 // those requests and not torn down organically. 1608 if (apnContext.getApnType() == PhoneConstants.APN_TYPE_DUN && teardownForDun()) { 1609 cleanup = true; 1610 } else { 1611 cleanup = false; 1612 } 1613 } else { 1614 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); 1615 } 1616 } else { 1617 if (enabled && met) { 1618 if (apnContext.isEnabled()) { 1619 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); 1620 } else { 1621 apnContext.setReason(Phone.REASON_DATA_ENABLED); 1622 } 1623 if (apnContext.getState() == DctConstants.State.FAILED) { 1624 apnContext.setState(DctConstants.State.IDLE); 1625 } 1626 trySetup = true; 1627 } 1628 } 1629 apnContext.setEnabled(enabled); 1630 apnContext.setDependencyMet(met); 1631 if (cleanup) cleanUpConnection(true, apnContext); 1632 if (trySetup) { 1633 apnContext.resetErrorCodeRetries(); 1634 trySetupData(apnContext); 1635 } 1636 } 1637 1638 private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) { 1639 String apnType = apnContext.getApnType(); 1640 ApnSetting dunSetting = null; 1641 1642 if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) { 1643 dunSetting = fetchDunApn(); 1644 } 1645 if (DBG) { 1646 log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext ); 1647 } 1648 1649 DcAsyncChannel potentialDcac = null; 1650 ApnContext potentialApnCtx = null; 1651 for (ApnContext curApnCtx : mApnContexts.values()) { 1652 DcAsyncChannel curDcac = curApnCtx.getDcAc(); 1653 if (curDcac != null) { 1654 ApnSetting apnSetting = curApnCtx.getApnSetting(); 1655 log("apnSetting: " + apnSetting); 1656 if (dunSetting != null) { 1657 if (dunSetting.equals(apnSetting)) { 1658 switch (curApnCtx.getState()) { 1659 case CONNECTED: 1660 if (DBG) { 1661 log("checkForCompatibleConnectedApnContext:" 1662 + " found dun conn=" + curDcac 1663 + " curApnCtx=" + curApnCtx); 1664 } 1665 return curDcac; 1666 case RETRYING: 1667 case CONNECTING: 1668 potentialDcac = curDcac; 1669 potentialApnCtx = curApnCtx; 1670 default: 1671 // Not connected, potential unchanged 1672 break; 1673 } 1674 } 1675 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) { 1676 switch (curApnCtx.getState()) { 1677 case CONNECTED: 1678 if (DBG) { 1679 log("checkForCompatibleConnectedApnContext:" 1680 + " found canHandle conn=" + curDcac 1681 + " curApnCtx=" + curApnCtx); 1682 } 1683 return curDcac; 1684 case RETRYING: 1685 case CONNECTING: 1686 potentialDcac = curDcac; 1687 potentialApnCtx = curApnCtx; 1688 default: 1689 // Not connected, potential unchanged 1690 break; 1691 } 1692 } 1693 } else { 1694 if (VDBG) { 1695 log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx); 1696 } 1697 } 1698 } 1699 if (potentialDcac != null) { 1700 if (DBG) { 1701 log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac 1702 + " curApnCtx=" + potentialApnCtx); 1703 } 1704 return potentialDcac; 1705 } 1706 1707 if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext); 1708 return null; 1709 } 1710 1711 @Override 1712 protected void onEnableApn(int apnId, int enabled) { 1713 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId)); 1714 if (apnContext == null) { 1715 loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext"); 1716 return; 1717 } 1718 // TODO change our retry manager to use the appropriate numbers for the new APN 1719 if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState"); 1720 applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet()); 1721 } 1722 1723 @Override 1724 // TODO: We shouldnt need this. 1725 protected boolean onTrySetupData(String reason) { 1726 if (DBG) log("onTrySetupData: reason=" + reason); 1727 setupDataOnConnectableApns(reason); 1728 return true; 1729 } 1730 1731 protected boolean onTrySetupData(ApnContext apnContext) { 1732 if (DBG) log("onTrySetupData: apnContext=" + apnContext); 1733 return trySetupData(apnContext); 1734 } 1735 1736 @Override 1737 protected void onRoamingOff() { 1738 if (DBG) log("onRoamingOff"); 1739 1740 if (!mUserDataEnabled) return; 1741 1742 if (getDataOnRoamingEnabled() == false) { 1743 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF); 1744 setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF); 1745 } else { 1746 notifyDataConnection(Phone.REASON_ROAMING_OFF); 1747 } 1748 } 1749 1750 @Override 1751 protected void onRoamingOn() { 1752 if (DBG) log("onRoamingOn"); 1753 1754 if (!mUserDataEnabled) return; 1755 1756 if (getDataOnRoamingEnabled()) { 1757 if (DBG) log("onRoamingOn: setup data on roaming"); 1758 setupDataOnConnectableApns(Phone.REASON_ROAMING_ON); 1759 notifyDataConnection(Phone.REASON_ROAMING_ON); 1760 } else { 1761 if (DBG) log("onRoamingOn: Tear down data connection on roaming."); 1762 cleanUpAllConnections(true, Phone.REASON_ROAMING_ON); 1763 notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON); 1764 } 1765 } 1766 1767 @Override 1768 protected void onRadioAvailable() { 1769 if (DBG) log("onRadioAvailable"); 1770 if (mPhone.getSimulatedRadioControl() != null) { 1771 // Assume data is connected on the simulator 1772 // FIXME this can be improved 1773 // setState(DctConstants.State.CONNECTED); 1774 notifyDataConnection(null); 1775 1776 log("onRadioAvailable: We're on the simulator; assuming data is connected"); 1777 } 1778 1779 IccRecords r = mIccRecords.get(); 1780 if (r != null && r.getRecordsLoaded()) { 1781 notifyOffApnsOfAvailability(null); 1782 } 1783 1784 if (getOverallState() != DctConstants.State.IDLE) { 1785 cleanUpConnection(true, null); 1786 } 1787 } 1788 1789 @Override 1790 protected void onRadioOffOrNotAvailable() { 1791 // Make sure our reconnect delay starts at the initial value 1792 // next time the radio comes on 1793 1794 mReregisterOnReconnectFailure = false; 1795 1796 if (mPhone.getSimulatedRadioControl() != null) { 1797 // Assume data is connected on the simulator 1798 // FIXME this can be improved 1799 log("We're on the simulator; assuming radio off is meaningless"); 1800 } else { 1801 if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); 1802 cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF); 1803 } 1804 notifyOffApnsOfAvailability(null); 1805 } 1806 1807 @Override 1808 protected void completeConnection(ApnContext apnContext) { 1809 boolean isProvApn = apnContext.isProvisioningApn(); 1810 1811 if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext); 1812 1813 if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) { 1814 if (DBG) { 1815 log("completeConnection: MOBILE_PROVISIONING_ACTION url=" 1816 + mProvisioningUrl); 1817 } 1818 Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, 1819 Intent.CATEGORY_APP_BROWSER); 1820 newIntent.setData(Uri.parse(mProvisioningUrl)); 1821 newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | 1822 Intent.FLAG_ACTIVITY_NEW_TASK); 1823 try { 1824 mPhone.getContext().startActivity(newIntent); 1825 } catch (ActivityNotFoundException e) { 1826 loge("completeConnection: startActivityAsUser failed" + e); 1827 } 1828 } 1829 mIsProvisioning = false; 1830 mProvisioningUrl = null; 1831 if (mProvisioningSpinner != null) { 1832 sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, 1833 mProvisioningSpinner)); 1834 } 1835 1836 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1837 startNetStatPoll(); 1838 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 1839 } 1840 1841 /** 1842 * A SETUP (aka bringUp) has completed, possibly with an error. If 1843 * there is an error this method will call {@link #onDataSetupCompleteError}. 1844 */ 1845 @Override 1846 protected void onDataSetupComplete(AsyncResult ar) { 1847 1848 DcFailCause cause = DcFailCause.UNKNOWN; 1849 boolean handleError = false; 1850 ApnContext apnContext = null; 1851 1852 if(ar.userObj instanceof ApnContext){ 1853 apnContext = (ApnContext)ar.userObj; 1854 } else { 1855 throw new RuntimeException("onDataSetupComplete: No apnContext"); 1856 } 1857 1858 if (ar.exception == null) { 1859 DcAsyncChannel dcac = apnContext.getDcAc(); 1860 1861 if (RADIO_TESTS) { 1862 // Note: To change radio.test.onDSC.null.dcac from command line you need to 1863 // adb root and adb remount and from the command line you can only change the 1864 // value to 1 once. To change it a second time you can reboot or execute 1865 // adb shell stop and then adb shell start. The command line to set the value is: 1866 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');" 1867 ContentResolver cr = mPhone.getContext().getContentResolver(); 1868 String radioTestProperty = "radio.test.onDSC.null.dcac"; 1869 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) { 1870 log("onDataSetupComplete: " + radioTestProperty + 1871 " is true, set dcac to null and reset property to false"); 1872 dcac = null; 1873 Settings.System.putInt(cr, radioTestProperty, 0); 1874 log("onDataSetupComplete: " + radioTestProperty + "=" + 1875 Settings.System.getInt(mPhone.getContext().getContentResolver(), 1876 radioTestProperty, -1)); 1877 } 1878 } 1879 if (dcac == null) { 1880 log("onDataSetupComplete: no connection to DC, handle as error"); 1881 cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN; 1882 handleError = true; 1883 } else { 1884 ApnSetting apn = apnContext.getApnSetting(); 1885 if (DBG) { 1886 log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn)); 1887 } 1888 if (apn != null && apn.proxy != null && apn.proxy.length() != 0) { 1889 try { 1890 String port = apn.port; 1891 if (TextUtils.isEmpty(port)) port = "8080"; 1892 ProxyInfo proxy = new ProxyInfo(apn.proxy, 1893 Integer.parseInt(port), null); 1894 dcac.setLinkPropertiesHttpProxySync(proxy); 1895 } catch (NumberFormatException e) { 1896 loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" + 1897 apn.port + "): " + e); 1898 } 1899 } 1900 1901 // everything is setup 1902 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) { 1903 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true"); 1904 if (mCanSetPreferApn && mPreferredApn == null) { 1905 if (DBG) log("onDataSetupComplete: PREFERED APN is null"); 1906 mPreferredApn = apn; 1907 if (mPreferredApn != null) { 1908 setPreferredApn(mPreferredApn.id); 1909 } 1910 } 1911 } else { 1912 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false"); 1913 } 1914 1915 // A connection is setup 1916 apnContext.setState(DctConstants.State.CONNECTED); 1917 boolean isProvApn = apnContext.isProvisioningApn(); 1918 final ConnectivityManager cm = ConnectivityManager.from(mPhone.getContext()); 1919 if (mProvisionBroadcastReceiver != null) { 1920 mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); 1921 mProvisionBroadcastReceiver = null; 1922 } 1923 if ((!isProvApn) || mIsProvisioning) { 1924 // Hide any provisioning notification. 1925 cm.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_MOBILE, 1926 mProvisionActionName); 1927 // Complete the connection normally notifying the world we're connected. 1928 // We do this if this isn't a special provisioning apn or if we've been 1929 // told its time to provision. 1930 completeConnection(apnContext); 1931 } else { 1932 // This is a provisioning APN that we're reporting as connected. Later 1933 // when the user desires to upgrade this to a "default" connection, 1934 // mIsProvisioning == true, we'll go through the code path above. 1935 // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING 1936 // is sent to the DCT. 1937 if (DBG) { 1938 log("onDataSetupComplete: successful, BUT send connected to prov apn as" 1939 + " mIsProvisioning:" + mIsProvisioning + " == false" 1940 + " && (isProvisioningApn:" + isProvApn + " == true"); 1941 } 1942 1943 // While radio is up, grab provisioning URL. The URL contains ICCID which 1944 // disappears when radio is off. 1945 mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver( 1946 cm.getMobileProvisioningUrl(), 1947 TelephonyManager.getDefault().getNetworkOperatorName()); 1948 mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver, 1949 new IntentFilter(mProvisionActionName)); 1950 // Put up user notification that sign-in is required. 1951 cm.setProvisioningNotificationVisible(true, ConnectivityManager.TYPE_MOBILE, 1952 mProvisionActionName); 1953 // Turn off radio to save battery and avoid wasting carrier resources. 1954 // The network isn't usable and network validation will just fail anyhow. 1955 setRadio(false); 1956 1957 Intent intent = new Intent( 1958 TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN); 1959 intent.putExtra(PhoneConstants.DATA_APN_KEY, apnContext.getApnSetting().apn); 1960 intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnContext.getApnType()); 1961 1962 String apnType = apnContext.getApnType(); 1963 LinkProperties linkProperties = getLinkProperties(apnType); 1964 if (linkProperties != null) { 1965 intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties); 1966 String iface = linkProperties.getInterfaceName(); 1967 if (iface != null) { 1968 intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface); 1969 } 1970 } 1971 NetworkCapabilities networkCapabilities = getNetworkCapabilities(apnType); 1972 if (networkCapabilities != null) { 1973 intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY, 1974 networkCapabilities); 1975 } 1976 1977 mPhone.getContext().sendBroadcastAsUser(intent, UserHandle.ALL); 1978 } 1979 if (DBG) { 1980 log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType() 1981 + ", reason:" + apnContext.getReason()); 1982 } 1983 } 1984 } else { 1985 cause = (DcFailCause) (ar.result); 1986 if (DBG) { 1987 ApnSetting apn = apnContext.getApnSetting(); 1988 log(String.format("onDataSetupComplete: error apn=%s cause=%s", 1989 (apn == null ? "unknown" : apn.apn), cause)); 1990 } 1991 if (cause.isEventLoggable()) { 1992 // Log this failure to the Event Logs. 1993 int cid = getCellLocationId(); 1994 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, 1995 cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType()); 1996 } 1997 ApnSetting apn = apnContext.getApnSetting(); 1998 mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(), 1999 apnContext.getApnType(), apn != null ? apn.apn : "unknown", cause.toString()); 2000 2001 // Count permanent failures and remove the APN we just tried 2002 if (isPermanentFail(cause)) apnContext.decWaitingApnsPermFailCount(); 2003 2004 apnContext.removeWaitingApn(apnContext.getApnSetting()); 2005 if (DBG) { 2006 log(String.format("onDataSetupComplete: WaitingApns.size=%d" + 2007 " WaitingApnsPermFailureCountDown=%d", 2008 apnContext.getWaitingApns().size(), 2009 apnContext.getWaitingApnsPermFailCount())); 2010 } 2011 handleError = true; 2012 } 2013 2014 if (handleError) { 2015 onDataSetupCompleteError(ar); 2016 } 2017 2018 /* If flag is set to false after SETUP_DATA_CALL is invoked, we need 2019 * to clean data connections. 2020 */ 2021 if (!mInternalDataEnabled) { 2022 cleanUpAllConnections(null); 2023 } 2024 2025 } 2026 2027 /** 2028 * @return number of milli-seconds to delay between trying apns' 2029 */ 2030 private int getApnDelay() { 2031 if (mFailFast) { 2032 return SystemProperties.getInt("persist.radio.apn_ff_delay", 2033 APN_FAIL_FAST_DELAY_DEFAULT_MILLIS); 2034 } else { 2035 return SystemProperties.getInt("persist.radio.apn_delay", APN_DELAY_DEFAULT_MILLIS); 2036 } 2037 } 2038 2039 /** 2040 * Error has occurred during the SETUP {aka bringUP} request and the DCT 2041 * should either try the next waiting APN or start over from the 2042 * beginning if the list is empty. Between each SETUP request there will 2043 * be a delay defined by {@link #getApnDelay()}. 2044 */ 2045 @Override 2046 protected void onDataSetupCompleteError(AsyncResult ar) { 2047 String reason = ""; 2048 ApnContext apnContext = null; 2049 2050 if(ar.userObj instanceof ApnContext){ 2051 apnContext = (ApnContext)ar.userObj; 2052 } else { 2053 throw new RuntimeException("onDataSetupCompleteError: No apnContext"); 2054 } 2055 2056 // See if there are more APN's to try 2057 if (apnContext.getWaitingApns().isEmpty()) { 2058 apnContext.setState(DctConstants.State.FAILED); 2059 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType()); 2060 2061 apnContext.setDataConnectionAc(null); 2062 2063 if (apnContext.getWaitingApnsPermFailCount() == 0) { 2064 if (DBG) { 2065 log("onDataSetupCompleteError: All APN's had permanent failures, stop retrying"); 2066 } 2067 } else { 2068 int delay = getApnDelay(); 2069 if (DBG) { 2070 log("onDataSetupCompleteError: Not all APN's had permanent failures delay=" 2071 + delay); 2072 } 2073 startAlarmForRestartTrySetup(delay, apnContext); 2074 } 2075 } else { 2076 if (DBG) log("onDataSetupCompleteError: Try next APN"); 2077 apnContext.setState(DctConstants.State.SCANNING); 2078 // Wait a bit before trying the next APN, so that 2079 // we're not tying up the RIL command channel 2080 startAlarmForReconnect(getApnDelay(), apnContext); 2081 } 2082 } 2083 2084 /** 2085 * Called when EVENT_DISCONNECT_DONE is received. 2086 */ 2087 @Override 2088 protected void onDisconnectDone(int connId, AsyncResult ar) { 2089 ApnContext apnContext = null; 2090 2091 if (ar.userObj instanceof ApnContext) { 2092 apnContext = (ApnContext) ar.userObj; 2093 } else { 2094 loge("onDisconnectDone: Invalid ar in onDisconnectDone, ignore"); 2095 return; 2096 } 2097 2098 if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext); 2099 apnContext.setState(DctConstants.State.IDLE); 2100 2101 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 2102 2103 // if all data connection are gone, check whether Airplane mode request was 2104 // pending. 2105 if (isDisconnected()) { 2106 if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { 2107 if(DBG) log("onDisconnectDone: radio will be turned off, no retries"); 2108 // Radio will be turned off. No need to retry data setup 2109 apnContext.setApnSetting(null); 2110 apnContext.setDataConnectionAc(null); 2111 2112 // Need to notify disconnect as well, in the case of switching Airplane mode. 2113 // Otherwise, it would cause 30s delayed to turn on Airplane mode. 2114 if (mDisconnectPendingCount > 0) 2115 mDisconnectPendingCount--; 2116 2117 if (mDisconnectPendingCount == 0) { 2118 notifyDataDisconnectComplete(); 2119 notifyAllDataDisconnected(); 2120 } 2121 return; 2122 } 2123 } 2124 2125 // If APN is still enabled, try to bring it back up automatically 2126 if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) { 2127 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false"); 2128 // Wait a bit before trying the next APN, so that 2129 // we're not tying up the RIL command channel. 2130 // This also helps in any external dependency to turn off the context. 2131 if(DBG) log("onDisconnectDone: attached, ready and retry after disconnect"); 2132 startAlarmForReconnect(getApnDelay(), apnContext); 2133 } else { 2134 boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean( 2135 com.android.internal.R.bool.config_restartRadioAfterProvisioning); 2136 2137 if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) { 2138 log("onDisconnectDone: restartRadio after provisioning"); 2139 restartRadio(); 2140 } 2141 apnContext.setApnSetting(null); 2142 apnContext.setDataConnectionAc(null); 2143 if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) { 2144 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn"); 2145 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION); 2146 } else { 2147 if(DBG) log("onDisconnectDone: not retrying"); 2148 } 2149 } 2150 2151 if (mDisconnectPendingCount > 0) 2152 mDisconnectPendingCount--; 2153 2154 if (mDisconnectPendingCount == 0) { 2155 apnContext.setConcurrentVoiceAndDataAllowed( 2156 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()); 2157 notifyDataDisconnectComplete(); 2158 notifyAllDataDisconnected(); 2159 } 2160 2161 } 2162 2163 /** 2164 * Called when EVENT_DISCONNECT_DC_RETRYING is received. 2165 */ 2166 @Override 2167 protected void onDisconnectDcRetrying(int connId, AsyncResult ar) { 2168 // We could just do this in DC!!! 2169 ApnContext apnContext = null; 2170 2171 if (ar.userObj instanceof ApnContext) { 2172 apnContext = (ApnContext) ar.userObj; 2173 } else { 2174 loge("onDisconnectDcRetrying: Invalid ar in onDisconnectDone, ignore"); 2175 return; 2176 } 2177 2178 apnContext.setState(DctConstants.State.RETRYING); 2179 if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext); 2180 2181 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 2182 } 2183 2184 2185 @Override 2186 protected void onVoiceCallStarted() { 2187 if (DBG) log("onVoiceCallStarted"); 2188 mInVoiceCall = true; 2189 if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 2190 if (DBG) log("onVoiceCallStarted stop polling"); 2191 stopNetStatPoll(); 2192 stopDataStallAlarm(); 2193 notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); 2194 } 2195 } 2196 2197 @Override 2198 protected void onVoiceCallEnded() { 2199 if (DBG) log("onVoiceCallEnded"); 2200 mInVoiceCall = false; 2201 if (isConnected()) { 2202 if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 2203 startNetStatPoll(); 2204 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 2205 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); 2206 } else { 2207 // clean slate after call end. 2208 resetPollStats(); 2209 } 2210 } 2211 // reset reconnect timer 2212 setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED); 2213 } 2214 2215 @Override 2216 protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) { 2217 if (DBG) log("onCleanUpConnection"); 2218 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId)); 2219 if (apnContext != null) { 2220 apnContext.setReason(reason); 2221 cleanUpConnection(tearDown, apnContext); 2222 } 2223 } 2224 2225 @Override 2226 protected boolean isConnected() { 2227 for (ApnContext apnContext : mApnContexts.values()) { 2228 if (apnContext.getState() == DctConstants.State.CONNECTED) { 2229 // At least one context is connected, return true 2230 return true; 2231 } 2232 } 2233 // There are not any contexts connected, return false 2234 return false; 2235 } 2236 2237 @Override 2238 public boolean isDisconnected() { 2239 for (ApnContext apnContext : mApnContexts.values()) { 2240 if (!apnContext.isDisconnected()) { 2241 // At least one context was not disconnected return false 2242 return false; 2243 } 2244 } 2245 // All contexts were disconnected so return true 2246 return true; 2247 } 2248 2249 @Override 2250 protected void notifyDataConnection(String reason) { 2251 if (DBG) log("notifyDataConnection: reason=" + reason); 2252 for (ApnContext apnContext : mApnContexts.values()) { 2253 if (mAttached.get() && apnContext.isReady()) { 2254 if (DBG) log("notifyDataConnection: type:" + apnContext.getApnType()); 2255 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 2256 apnContext.getApnType()); 2257 } 2258 } 2259 notifyOffApnsOfAvailability(reason); 2260 } 2261 2262 /** 2263 * Based on the sim operator numeric, create a list for all possible 2264 * Data Connections and setup the preferredApn. 2265 */ 2266 private void createAllApnList() { 2267 mAllApnSettings = new ArrayList<ApnSetting>(); 2268 IccRecords r = mIccRecords.get(); 2269 String operator = (r != null) ? r.getOperatorNumeric() : ""; 2270 if (operator != null) { 2271 String selection = "numeric = '" + operator + "'"; 2272 String orderBy = "_id"; 2273 // query only enabled apn. 2274 // carrier_enabled : 1 means enabled apn, 0 disabled apn. 2275 // selection += " and carrier_enabled = 1"; 2276 if (DBG) log("createAllApnList: selection=" + selection); 2277 2278 Cursor cursor = mPhone.getContext().getContentResolver().query( 2279 Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy); 2280 2281 if (cursor != null) { 2282 if (cursor.getCount() > 0) { 2283 mAllApnSettings = createApnList(cursor); 2284 } 2285 cursor.close(); 2286 } 2287 } 2288 2289 addEmergencyApnSetting(); 2290 2291 dedupeApnSettings(); 2292 2293 if (mAllApnSettings.isEmpty()) { 2294 if (DBG) log("createAllApnList: No APN found for carrier: " + operator); 2295 mPreferredApn = null; 2296 // TODO: What is the right behavior? 2297 //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN); 2298 } else { 2299 mPreferredApn = getPreferredApn(); 2300 if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { 2301 mPreferredApn = null; 2302 setPreferredApn(-1); 2303 } 2304 if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); 2305 } 2306 if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); 2307 2308 setDataProfilesAsNeeded(); 2309 } 2310 2311 private void dedupeApnSettings() { 2312 ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>(); 2313 2314 // coalesce APNs if they are similar enough to prevent 2315 // us from bringing up two data calls with the same interface 2316 int i = 0; 2317 while (i < mAllApnSettings.size() - 1) { 2318 ApnSetting first = mAllApnSettings.get(i); 2319 ApnSetting second = null; 2320 int j = i + 1; 2321 while (j < mAllApnSettings.size()) { 2322 second = mAllApnSettings.get(j); 2323 if (apnsSimilar(first, second)) { 2324 ApnSetting newApn = mergeApns(first, second); 2325 mAllApnSettings.set(i, newApn); 2326 first = newApn; 2327 mAllApnSettings.remove(j); 2328 } else { 2329 j++; 2330 } 2331 } 2332 i++; 2333 } 2334 } 2335 2336 //check whether the types of two APN same (even only one type of each APN is same) 2337 private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) { 2338 if(VDBG) { 2339 StringBuilder apnType1 = new StringBuilder(first.apn + ": "); 2340 for(int index1 = 0; index1 < first.types.length; index1++) { 2341 apnType1.append(first.types[index1]); 2342 apnType1.append(","); 2343 } 2344 2345 StringBuilder apnType2 = new StringBuilder(second.apn + ": "); 2346 for(int index1 = 0; index1 < second.types.length; index1++) { 2347 apnType2.append(second.types[index1]); 2348 apnType2.append(","); 2349 } 2350 log("APN1: is " + apnType1); 2351 log("APN2: is " + apnType2); 2352 } 2353 2354 for(int index1 = 0; index1 < first.types.length; index1++) { 2355 for(int index2 = 0; index2 < second.types.length; index2++) { 2356 if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || 2357 second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || 2358 first.types[index1].equals(second.types[index2])) { 2359 if(VDBG)log("apnTypeSameAny: return true"); 2360 return true; 2361 } 2362 } 2363 } 2364 2365 if(VDBG)log("apnTypeSameAny: return false"); 2366 return false; 2367 } 2368 2369 // Check if neither mention DUN and are substantially similar 2370 private boolean apnsSimilar(ApnSetting first, ApnSetting second) { 2371 return (first.canHandleType(PhoneConstants.APN_TYPE_DUN) == false && 2372 second.canHandleType(PhoneConstants.APN_TYPE_DUN) == false && 2373 Objects.equals(first.apn, second.apn) && 2374 !apnTypeSameAny(first, second) && 2375 xorEquals(first.proxy, second.proxy) && 2376 xorEquals(first.port, second.port) && 2377 first.carrierEnabled == second.carrierEnabled && 2378 first.bearerBitmask == second.bearerBitmask && 2379 first.profileId == second.profileId && 2380 Objects.equals(first.mvnoType, second.mvnoType) && 2381 Objects.equals(first.mvnoMatchData, second.mvnoMatchData) && 2382 xorEquals(first.mmsc, second.mmsc) && 2383 xorEquals(first.mmsProxy, second.mmsProxy) && 2384 xorEquals(first.mmsPort, second.mmsPort)); 2385 } 2386 2387 // equal or one is not specified 2388 private boolean xorEquals(String first, String second) { 2389 return (Objects.equals(first, second) || 2390 TextUtils.isEmpty(first) || 2391 TextUtils.isEmpty(second)); 2392 } 2393 2394 private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { 2395 int id = dest.id; 2396 ArrayList<String> resultTypes = new ArrayList<String>(); 2397 resultTypes.addAll(Arrays.asList(dest.types)); 2398 for (String srcType : src.types) { 2399 if (resultTypes.contains(srcType) == false) resultTypes.add(srcType); 2400 if (srcType.equals(PhoneConstants.APN_TYPE_DEFAULT)) id = src.id; 2401 } 2402 String mmsc = (TextUtils.isEmpty(dest.mmsc) ? src.mmsc : dest.mmsc); 2403 String mmsProxy = (TextUtils.isEmpty(dest.mmsProxy) ? src.mmsProxy : dest.mmsProxy); 2404 String mmsPort = (TextUtils.isEmpty(dest.mmsPort) ? src.mmsPort : dest.mmsPort); 2405 String proxy = (TextUtils.isEmpty(dest.proxy) ? src.proxy : dest.proxy); 2406 String port = (TextUtils.isEmpty(dest.port) ? src.port : dest.port); 2407 String protocol = src.protocol.equals("IPV4V6") ? src.protocol : dest.protocol; 2408 String roamingProtocol = src.roamingProtocol.equals("IPV4V6") ? src.roamingProtocol : 2409 dest.roamingProtocol; 2410 int bearerBitmask = (dest.bearerBitmask == 0 || src.bearerBitmask == 0) ? 2411 0 : (dest.bearerBitmask | src.bearerBitmask); 2412 2413 return new ApnSetting(id, dest.numeric, dest.carrier, dest.apn, 2414 proxy, port, mmsc, mmsProxy, mmsPort, dest.user, dest.password, 2415 dest.authType, resultTypes.toArray(new String[0]), protocol, 2416 roamingProtocol, dest.carrierEnabled, 0, bearerBitmask, dest.profileId, 2417 (dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime, 2418 dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData); 2419 } 2420 2421 /** Return the DC AsyncChannel for the new data connection */ 2422 private DcAsyncChannel createDataConnection() { 2423 if (DBG) log("createDataConnection E"); 2424 2425 int id = mUniqueIdGenerator.getAndIncrement(); 2426 DataConnection conn = DataConnection.makeDataConnection(mPhone, id, 2427 this, mDcTesterFailBringUpAll, mDcc); 2428 mDataConnections.put(id, conn); 2429 DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG); 2430 int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler()); 2431 if (status == AsyncChannel.STATUS_SUCCESSFUL) { 2432 mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac); 2433 } else { 2434 loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status); 2435 } 2436 2437 if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn); 2438 return dcac; 2439 } 2440 2441 private void destroyDataConnections() { 2442 if(mDataConnections != null) { 2443 if (DBG) log("destroyDataConnections: clear mDataConnectionList"); 2444 mDataConnections.clear(); 2445 } else { 2446 if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); 2447 } 2448 } 2449 2450 /** 2451 * Build a list of APNs to be used to create PDP's. 2452 * 2453 * @param requestedApnType 2454 * @return waitingApns list to be used to create PDP 2455 * error when waitingApns.isEmpty() 2456 */ 2457 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) { 2458 if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); 2459 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); 2460 2461 if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) { 2462 ApnSetting dun = fetchDunApn(); 2463 if (dun != null) { 2464 apnList.add(dun); 2465 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); 2466 return apnList; 2467 } 2468 } 2469 2470 IccRecords r = mIccRecords.get(); 2471 String operator = (r != null) ? r.getOperatorNumeric() : ""; 2472 2473 // This is a workaround for a bug (7305641) where we don't failover to other 2474 // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to 2475 // failover to a provisioning APN, but once we've used their default data 2476 // connection we are locked to it for life. This change allows ATT devices 2477 // to say they don't want to use preferred at all. 2478 boolean usePreferred = true; 2479 try { 2480 usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android. 2481 internal.R.bool.config_dontPreferApn); 2482 } catch (Resources.NotFoundException e) { 2483 if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); 2484 usePreferred = true; 2485 } 2486 if (usePreferred) { 2487 mPreferredApn = getPreferredApn(); 2488 } 2489 if (DBG) { 2490 log("buildWaitingApns: usePreferred=" + usePreferred 2491 + " canSetPreferApn=" + mCanSetPreferApn 2492 + " mPreferredApn=" + mPreferredApn 2493 + " operator=" + operator + " radioTech=" + radioTech 2494 + " IccRecords r=" + r); 2495 } 2496 2497 if (usePreferred && mCanSetPreferApn && mPreferredApn != null && 2498 mPreferredApn.canHandleType(requestedApnType)) { 2499 if (DBG) { 2500 log("buildWaitingApns: Preferred APN:" + operator + ":" 2501 + mPreferredApn.numeric + ":" + mPreferredApn); 2502 } 2503 if (mPreferredApn.numeric.equals(operator)) { 2504 if (ServiceState.bitmaskHasTech(mPreferredApn.bearerBitmask, radioTech)) { 2505 apnList.add(mPreferredApn); 2506 if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); 2507 return apnList; 2508 } else { 2509 if (DBG) log("buildWaitingApns: no preferred APN"); 2510 setPreferredApn(-1); 2511 mPreferredApn = null; 2512 } 2513 } else { 2514 if (DBG) log("buildWaitingApns: no preferred APN"); 2515 setPreferredApn(-1); 2516 mPreferredApn = null; 2517 } 2518 } 2519 if (mAllApnSettings != null) { 2520 if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); 2521 for (ApnSetting apn : mAllApnSettings) { 2522 if (apn.canHandleType(requestedApnType)) { 2523 if (ServiceState.bitmaskHasTech(apn.bearerBitmask, radioTech)) { 2524 if (DBG) log("buildWaitingApns: adding apn=" + apn); 2525 apnList.add(apn); 2526 } else { 2527 if (DBG) { 2528 log("buildWaitingApns: bearerBitmask:" + apn.bearerBitmask + " does " + 2529 "not include radioTech:" + radioTech); 2530 } 2531 } 2532 } else if (DBG) { 2533 log("buildWaitingApns: couldn't handle requesedApnType=" 2534 + requestedApnType); 2535 } 2536 } 2537 } else { 2538 loge("mAllApnSettings is null!"); 2539 } 2540 if (DBG) log("buildWaitingApns: X apnList=" + apnList); 2541 return apnList; 2542 } 2543 2544 private String apnListToString (ArrayList<ApnSetting> apns) { 2545 StringBuilder result = new StringBuilder(); 2546 for (int i = 0, size = apns.size(); i < size; i++) { 2547 result.append('[') 2548 .append(apns.get(i).toString()) 2549 .append(']'); 2550 } 2551 return result.toString(); 2552 } 2553 2554 private void setPreferredApn(int pos) { 2555 if (!mCanSetPreferApn) { 2556 log("setPreferredApn: X !canSEtPreferApn"); 2557 return; 2558 } 2559 2560 String subId = Long.toString(mPhone.getSubId()); 2561 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 2562 log("setPreferredApn: delete"); 2563 ContentResolver resolver = mPhone.getContext().getContentResolver(); 2564 resolver.delete(uri, null, null); 2565 2566 if (pos >= 0) { 2567 log("setPreferredApn: insert"); 2568 ContentValues values = new ContentValues(); 2569 values.put(APN_ID, pos); 2570 resolver.insert(uri, values); 2571 } 2572 } 2573 2574 private ApnSetting getPreferredApn() { 2575 if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { 2576 log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty")); 2577 return null; 2578 } 2579 2580 String subId = Long.toString(mPhone.getSubId()); 2581 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 2582 Cursor cursor = mPhone.getContext().getContentResolver().query( 2583 uri, new String[] { "_id", "name", "apn" }, 2584 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 2585 2586 if (cursor != null) { 2587 mCanSetPreferApn = true; 2588 } else { 2589 mCanSetPreferApn = false; 2590 } 2591 log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor 2592 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); 2593 2594 if (mCanSetPreferApn && cursor.getCount() > 0) { 2595 int pos; 2596 cursor.moveToFirst(); 2597 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); 2598 for(ApnSetting p : mAllApnSettings) { 2599 log("getPreferredApn: apnSetting=" + p); 2600 if (p.id == pos && p.canHandleType(mRequestedApnType)) { 2601 log("getPreferredApn: X found apnSetting" + p); 2602 cursor.close(); 2603 return p; 2604 } 2605 } 2606 } 2607 2608 if (cursor != null) { 2609 cursor.close(); 2610 } 2611 2612 log("getPreferredApn: X not found"); 2613 return null; 2614 } 2615 2616 @Override 2617 public void handleMessage (Message msg) { 2618 if (DBG) log("handleMessage msg=" + msg); 2619 2620 if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) { 2621 loge("handleMessage: Ignore GSM msgs since GSM phone is inactive"); 2622 return; 2623 } 2624 2625 switch (msg.what) { 2626 case DctConstants.EVENT_RECORDS_LOADED: 2627 onRecordsLoaded(); 2628 break; 2629 2630 case DctConstants.EVENT_DATA_CONNECTION_DETACHED: 2631 onDataConnectionDetached(); 2632 break; 2633 2634 case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: 2635 onDataConnectionAttached(); 2636 break; 2637 2638 case DctConstants.EVENT_DO_RECOVERY: 2639 doRecovery(); 2640 break; 2641 2642 case DctConstants.EVENT_APN_CHANGED: 2643 onApnChanged(); 2644 break; 2645 2646 case DctConstants.EVENT_PS_RESTRICT_ENABLED: 2647 /** 2648 * We don't need to explicitly to tear down the PDP context 2649 * when PS restricted is enabled. The base band will deactive 2650 * PDP context and notify us with PDP_CONTEXT_CHANGED. 2651 * But we should stop the network polling and prevent reset PDP. 2652 */ 2653 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); 2654 stopNetStatPoll(); 2655 stopDataStallAlarm(); 2656 mIsPsRestricted = true; 2657 break; 2658 2659 case DctConstants.EVENT_PS_RESTRICT_DISABLED: 2660 /** 2661 * When PS restrict is removed, we need setup PDP connection if 2662 * PDP connection is down. 2663 */ 2664 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); 2665 mIsPsRestricted = false; 2666 if (isConnected()) { 2667 startNetStatPoll(); 2668 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 2669 } else { 2670 // TODO: Should all PDN states be checked to fail? 2671 if (mState == DctConstants.State.FAILED) { 2672 cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED); 2673 mReregisterOnReconnectFailure = false; 2674 } 2675 ApnContext apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT); 2676 if (apnContext != null) { 2677 apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); 2678 trySetupData(apnContext); 2679 } else { 2680 loge("**** Default ApnContext not found ****"); 2681 if (Build.IS_DEBUGGABLE) { 2682 throw new RuntimeException("Default ApnContext not found"); 2683 } 2684 } 2685 } 2686 break; 2687 2688 case DctConstants.EVENT_TRY_SETUP_DATA: 2689 if (msg.obj instanceof ApnContext) { 2690 onTrySetupData((ApnContext)msg.obj); 2691 } else if (msg.obj instanceof String) { 2692 onTrySetupData((String)msg.obj); 2693 } else { 2694 loge("EVENT_TRY_SETUP request w/o apnContext or String"); 2695 } 2696 break; 2697 2698 case DctConstants.EVENT_CLEAN_UP_CONNECTION: 2699 boolean tearDown = (msg.arg1 == 0) ? false : true; 2700 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown); 2701 if (msg.obj instanceof ApnContext) { 2702 cleanUpConnection(tearDown, (ApnContext)msg.obj); 2703 } else { 2704 loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context, call super"); 2705 super.handleMessage(msg); 2706 } 2707 break; 2708 case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: 2709 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 2710 onSetInternalDataEnabled(enabled, (Message) msg.obj); 2711 break; 2712 2713 case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: 2714 Message mCause = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null); 2715 if ((msg.obj != null) && (msg.obj instanceof String)) { 2716 mCause.obj = msg.obj; 2717 } 2718 super.handleMessage(mCause); 2719 break; 2720 2721 case DctConstants.EVENT_DATA_RAT_CHANGED: 2722 //May new Network allow setupData, so try it here 2723 setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED, 2724 RetryFailures.ONLY_ON_CHANGE); 2725 break; 2726 2727 case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: 2728 // Check message sender intended to clear the current spinner. 2729 if (mProvisioningSpinner == msg.obj) { 2730 mProvisioningSpinner.dismiss(); 2731 mProvisioningSpinner = null; 2732 } 2733 break; 2734 2735 default: 2736 // handle the message in the super class DataConnectionTracker 2737 super.handleMessage(msg); 2738 break; 2739 } 2740 } 2741 2742 protected int getApnProfileID(String apnType) { 2743 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 2744 return RILConstants.DATA_PROFILE_IMS; 2745 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) { 2746 return RILConstants.DATA_PROFILE_FOTA; 2747 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) { 2748 return RILConstants.DATA_PROFILE_CBS; 2749 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IA)) { 2750 return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now 2751 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_DUN)) { 2752 return RILConstants.DATA_PROFILE_TETHERED; 2753 } else { 2754 return RILConstants.DATA_PROFILE_DEFAULT; 2755 } 2756 } 2757 2758 private int getCellLocationId() { 2759 int cid = -1; 2760 CellLocation loc = mPhone.getCellLocation(); 2761 2762 if (loc != null) { 2763 if (loc instanceof GsmCellLocation) { 2764 cid = ((GsmCellLocation)loc).getCid(); 2765 } else if (loc instanceof CdmaCellLocation) { 2766 cid = ((CdmaCellLocation)loc).getBaseStationId(); 2767 } 2768 } 2769 return cid; 2770 } 2771 2772 private IccRecords getUiccRecords(int appFamily) { 2773 return mUiccController.getIccRecords(mPhone.getPhoneId(), appFamily); 2774 } 2775 2776 2777 @Override 2778 protected void onUpdateIcc() { 2779 if (mUiccController == null ) { 2780 return; 2781 } 2782 2783 IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP); 2784 2785 IccRecords r = mIccRecords.get(); 2786 if (r != newIccRecords) { 2787 if (r != null) { 2788 log("Removing stale icc objects."); 2789 r.unregisterForRecordsLoaded(this); 2790 mIccRecords.set(null); 2791 } 2792 if (newIccRecords != null) { 2793 log("New records found"); 2794 mIccRecords.set(newIccRecords); 2795 newIccRecords.registerForRecordsLoaded( 2796 this, DctConstants.EVENT_RECORDS_LOADED, null); 2797 } else { 2798 onSimNotReady(); 2799 } 2800 } 2801 } 2802 2803 public void update() { 2804 log("update sub = " + mPhone.getSubId()); 2805 log("update(): Active DDS, register for all events now!"); 2806 registerForAllEvents(); 2807 onUpdateIcc(); 2808 2809 mUserDataEnabled = getDataEnabled(); 2810 2811 if (mPhone instanceof CDMALTEPhone) { 2812 ((CDMALTEPhone)mPhone).updateCurrentCarrierInProvider(); 2813 } else if (mPhone instanceof GSMPhone) { 2814 ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); 2815 } else { 2816 log("Phone object is not MultiSim. This should not hit!!!!"); 2817 } 2818 } 2819 2820 @Override 2821 public void cleanUpAllConnections(String cause) { 2822 cleanUpAllConnections(cause, null); 2823 } 2824 2825 public void updateRecords() { 2826 onUpdateIcc(); 2827 } 2828 2829 public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) { 2830 log("cleanUpAllConnections"); 2831 if (disconnectAllCompleteMsg != null) { 2832 mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg); 2833 } 2834 2835 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); 2836 msg.obj = cause; 2837 sendMessage(msg); 2838 } 2839 2840 protected void notifyDataDisconnectComplete() { 2841 log("notifyDataDisconnectComplete"); 2842 for (Message m: mDisconnectAllCompleteMsgList) { 2843 m.sendToTarget(); 2844 } 2845 mDisconnectAllCompleteMsgList.clear(); 2846 } 2847 2848 2849 protected void notifyAllDataDisconnected() { 2850 sEnableFailFastRefCounter = 0; 2851 mFailFast = false; 2852 mAllDataDisconnectedRegistrants.notifyRegistrants(); 2853 } 2854 2855 public void registerForAllDataDisconnected(Handler h, int what, Object obj) { 2856 mAllDataDisconnectedRegistrants.addUnique(h, what, obj); 2857 2858 if (isDisconnected()) { 2859 log("notify All Data Disconnected"); 2860 notifyAllDataDisconnected(); 2861 } 2862 } 2863 2864 public void unregisterForAllDataDisconnected(Handler h) { 2865 mAllDataDisconnectedRegistrants.remove(h); 2866 } 2867 2868 2869 @Override 2870 protected void onSetInternalDataEnabled(boolean enable) { 2871 if (DBG) log("onSetInternalDataEnabled: enabled=" + enable); 2872 onSetInternalDataEnabled(enable, null); 2873 } 2874 2875 protected void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) { 2876 if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled); 2877 boolean sendOnComplete = true; 2878 2879 synchronized (mDataEnabledLock) { 2880 mInternalDataEnabled = enabled; 2881 if (enabled) { 2882 log("onSetInternalDataEnabled: changed to enabled, try to setup data call"); 2883 onTrySetupData(Phone.REASON_DATA_ENABLED); 2884 } else { 2885 sendOnComplete = false; 2886 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections"); 2887 cleanUpAllConnections(null, onCompleteMsg); 2888 } 2889 } 2890 2891 if (sendOnComplete) { 2892 if (onCompleteMsg != null) { 2893 onCompleteMsg.sendToTarget(); 2894 } 2895 } 2896 } 2897 2898 public boolean setInternalDataEnabledFlag(boolean enable) { 2899 if (DBG) log("setInternalDataEnabledFlag(" + enable + ")"); 2900 2901 if (mInternalDataEnabled != enable) { 2902 mInternalDataEnabled = enable; 2903 } 2904 return true; 2905 } 2906 2907 @Override 2908 public boolean setInternalDataEnabled(boolean enable) { 2909 return setInternalDataEnabled(enable, null); 2910 } 2911 2912 public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) { 2913 if (DBG) log("setInternalDataEnabled(" + enable + ")"); 2914 2915 Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg); 2916 msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 2917 sendMessage(msg); 2918 return true; 2919 } 2920 2921 public void setDataAllowed(boolean enable, Message response) { 2922 if (DBG) log("setDataAllowed: enable=" + enable); 2923 mIsCleanupRequired = !enable; 2924 mPhone.mCi.setDataAllowed(enable, response); 2925 mInternalDataEnabled = enable; 2926 } 2927 2928 @Override 2929 protected void log(String s) { 2930 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 2931 } 2932 2933 @Override 2934 protected void loge(String s) { 2935 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 2936 } 2937 2938 @Override 2939 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2940 pw.println("DcTracker extends:"); 2941 super.dump(fd, pw, args); 2942 pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); 2943 pw.println(" canSetPreferApn=" + mCanSetPreferApn); 2944 pw.println(" mApnObserver=" + mApnObserver); 2945 pw.println(" getOverallState=" + getOverallState()); 2946 pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap); 2947 pw.println(" mAttached=" + mAttached.get()); 2948 } 2949 2950 @Override 2951 public String[] getPcscfAddress(String apnType) { 2952 log("getPcscfAddress()"); 2953 ApnContext apnContext = null; 2954 2955 if(apnType == null){ 2956 log("apnType is null, return null"); 2957 return null; 2958 } 2959 2960 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_EMERGENCY)) { 2961 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_EMERGENCY); 2962 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 2963 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_IMS); 2964 } else { 2965 log("apnType is invalid, return null"); 2966 return null; 2967 } 2968 2969 if (apnContext == null) { 2970 log("apnContext is null, return null"); 2971 return null; 2972 } 2973 2974 DcAsyncChannel dcac = apnContext.getDcAc(); 2975 String[] result = null; 2976 2977 if (dcac != null) { 2978 result = dcac.getPcscfAddr(); 2979 2980 for (int i = 0; i < result.length; i++) { 2981 log("Pcscf[" + i + "]: " + result[i]); 2982 } 2983 return result; 2984 } 2985 return null; 2986 } 2987 2988 @Override 2989 public void setImsRegistrationState(boolean registered) { 2990 log("setImsRegistrationState - mImsRegistrationState(before): "+ mImsRegistrationState 2991 + ", registered(current) : " + registered); 2992 2993 if (mPhone == null) return; 2994 2995 ServiceStateTracker sst = mPhone.getServiceStateTracker(); 2996 if (sst == null) return; 2997 2998 sst.setImsRegistrationState(registered); 2999 } 3000 3001 /** 3002 * Read APN configuration from Telephony.db for Emergency APN 3003 * All opertors recognize the connection request for EPDN based on APN type 3004 * PLMN name,APN name are not mandatory parameters 3005 */ 3006 private void initEmergencyApnSetting() { 3007 // Operator Numeric is not available when sim records are not loaded. 3008 // Query Telephony.db with APN type as EPDN request does not 3009 // require APN name, plmn and all operators support same APN config. 3010 // DB will contain only one entry for Emergency APN 3011 String selection = "type=\"emergency\""; 3012 Cursor cursor = mPhone.getContext().getContentResolver().query( 3013 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 3014 3015 if (cursor != null) { 3016 if (cursor.getCount() > 0) { 3017 if (cursor.moveToFirst()) { 3018 mEmergencyApn = makeApnSetting(cursor); 3019 } 3020 } 3021 cursor.close(); 3022 } 3023 } 3024 3025 /** 3026 * Add the Emergency APN settings to APN settings list 3027 */ 3028 private void addEmergencyApnSetting() { 3029 if(mEmergencyApn != null) { 3030 if(mAllApnSettings == null) { 3031 mAllApnSettings = new ArrayList<ApnSetting>(); 3032 } else { 3033 boolean hasEmergencyApn = false; 3034 for (ApnSetting apn : mAllApnSettings) { 3035 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) { 3036 hasEmergencyApn = true; 3037 break; 3038 } 3039 } 3040 3041 if(hasEmergencyApn == false) { 3042 mAllApnSettings.add(mEmergencyApn); 3043 } else { 3044 log("addEmergencyApnSetting - E-APN setting is already present"); 3045 } 3046 } 3047 } 3048 } 3049 3050 private void cleanUpConnectionsOnUpdatedApns(boolean tearDown) { 3051 if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown); 3052 if (mAllApnSettings.isEmpty()) { 3053 cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED); 3054 } else { 3055 for (ApnContext apnContext : mApnContexts.values()) { 3056 if (VDBG) log("cleanUpConnectionsOnUpdatedApns for "+ apnContext); 3057 3058 boolean cleanUpApn = true; 3059 ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns(); 3060 3061 if ((currentWaitingApns != null) && (!apnContext.isDisconnected())) { 3062 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 3063 ArrayList<ApnSetting> waitingApns = buildWaitingApns( 3064 apnContext.getApnType(), radioTech); 3065 if (VDBG) log("new waitingApns:" + waitingApns); 3066 if (waitingApns.size() == currentWaitingApns.size()) { 3067 cleanUpApn = false; 3068 for (int i = 0; i < waitingApns.size(); i++) { 3069 if (!currentWaitingApns.get(i).equals(waitingApns.get(i))) { 3070 if (VDBG) log("new waiting apn is different at " + i); 3071 cleanUpApn = true; 3072 apnContext.setWaitingApns(waitingApns); 3073 break; 3074 } 3075 } 3076 } 3077 } 3078 3079 if (cleanUpApn) { 3080 apnContext.setReason(Phone.REASON_APN_CHANGED); 3081 cleanUpConnection(true, apnContext); 3082 } 3083 } 3084 } 3085 3086 if (!isConnected()) { 3087 stopNetStatPoll(); 3088 stopDataStallAlarm(); 3089 } 3090 3091 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 3092 3093 if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount); 3094 if (tearDown && mDisconnectPendingCount == 0) { 3095 notifyDataDisconnectComplete(); 3096 notifyAllDataDisconnected(); 3097 } 3098 } 3099} 3100