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