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