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