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