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