DcTracker.java revision b79f845a0451895b0f0b8a926a8571511d476ce8
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony.dataconnection; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.app.ProgressDialog; 22import android.content.ActivityNotFoundException; 23import android.content.BroadcastReceiver; 24import android.content.ContentResolver; 25import android.content.ContentValues; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.res.Resources; 30import android.database.ContentObserver; 31import android.database.Cursor; 32import android.net.ConnectivityManager; 33import android.net.LinkProperties; 34import android.net.NetworkCapabilities; 35import android.net.NetworkConfig; 36import android.net.NetworkUtils; 37import android.net.ProxyInfo; 38import android.net.Uri; 39import android.os.AsyncResult; 40import android.os.Build; 41import android.os.Bundle; 42import android.os.Handler; 43import android.os.Looper; 44import android.os.Message; 45import android.os.Messenger; 46import android.os.RegistrantList; 47import android.os.ServiceManager; 48import android.os.SystemClock; 49import android.os.SystemProperties; 50import android.os.UserHandle; 51import android.provider.Settings; 52import android.provider.Telephony; 53import android.telephony.CellLocation; 54import android.telephony.ServiceState; 55import android.telephony.TelephonyManager; 56import android.telephony.SubscriptionManager; 57import android.telephony.cdma.CdmaCellLocation; 58import android.telephony.gsm.GsmCellLocation; 59import android.text.TextUtils; 60import android.util.EventLog; 61import android.util.SparseArray; 62import android.view.WindowManager; 63import android.telephony.Rlog; 64 65import com.android.internal.telephony.cdma.CDMALTEPhone; 66import com.android.internal.telephony.Phone; 67import com.android.internal.telephony.PhoneBase; 68import com.android.internal.telephony.DctConstants; 69import com.android.internal.telephony.EventLogTags; 70import com.android.internal.telephony.ITelephony; 71import com.android.internal.telephony.TelephonyIntents; 72import com.android.internal.telephony.gsm.GSMPhone; 73import com.android.internal.telephony.PhoneConstants; 74import com.android.internal.telephony.RILConstants; 75import com.android.internal.telephony.uicc.IccRecords; 76import com.android.internal.telephony.uicc.UiccController; 77import com.android.internal.util.AsyncChannel; 78import com.android.internal.util.ArrayUtils; 79 80import java.io.FileDescriptor; 81import java.io.PrintWriter; 82import java.util.ArrayList; 83import java.util.Arrays; 84import java.util.concurrent.atomic.AtomicBoolean; 85import java.util.Objects; 86import java.lang.StringBuilder; 87 88import android.provider.Settings; 89 90import com.android.internal.telephony.ServiceStateTracker; 91/** 92 * {@hide} 93 */ 94public final class DcTracker extends DcTrackerBase { 95 protected final String LOG_TAG = "DCT"; 96 97 /** 98 * List of messages that are waiting to be posted, when data call disconnect 99 * is complete 100 */ 101 private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>(); 102 103 private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); 104 105 protected int mDisconnectPendingCount = 0; 106 107 /** 108 * Handles changes to the APN db. 109 */ 110 private class ApnChangeObserver extends ContentObserver { 111 public ApnChangeObserver () { 112 super(mDataConnectionTracker); 113 } 114 115 @Override 116 public void onChange(boolean selfChange) { 117 sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); 118 } 119 } 120 121 //***** Instance Variables 122 123 private boolean mReregisterOnReconnectFailure = false; 124 125 126 //***** Constants 127 128 // Used by puppetmaster/*/radio_stress.py 129 private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active"; 130 131 private static final int POLL_PDP_MILLIS = 5 * 1000; 132 133 private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; 134 135 static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = 136 Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); 137 static final String APN_ID = "apn_id"; 138 139 private boolean mCanSetPreferApn = false; 140 141 private AtomicBoolean mAttached = new AtomicBoolean(false); 142 143 /** Watches for changes to the APN db. */ 144 private ApnChangeObserver mApnObserver; 145 146 private final String mProvisionActionName; 147 private BroadcastReceiver mProvisionBroadcastReceiver; 148 private ProgressDialog mProvisioningSpinner; 149 150 public boolean mImsRegistrationState = false; 151 private ApnContext mWaitCleanUpApnContext = null; 152 private boolean mDeregistrationAlarmState = false; 153 private PendingIntent mImsDeregistrationDelayIntent = null; 154 155 //***** Constructor 156 public DcTracker(PhoneBase p) { 157 super(p); 158 if (DBG) log("GsmDCT.constructor"); 159 160 mDataConnectionTracker = this; 161 update(); 162 mApnObserver = new ApnChangeObserver(); 163 p.getContext().getContentResolver().registerContentObserver( 164 Telephony.Carriers.CONTENT_URI, true, mApnObserver); 165 166 initApnContexts(); 167 168 for (ApnContext apnContext : mApnContexts.values()) { 169 // Register the reconnect and restart actions. 170 IntentFilter filter = new IntentFilter(); 171 filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType()); 172 filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType()); 173 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 174 } 175 176 // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases 177 initEmergencyApnSetting(); 178 addEmergencyApnSetting(); 179 180 mProvisionActionName = "com.android.internal.telephony.PROVISION" + p.getPhoneId(); 181 } 182 183 protected void registerForAllEvents() { 184 mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); 185 mPhone.mCi.registerForOffOrNotAvailable(this, 186 DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); 187 mPhone.mCi.registerForDataNetworkStateChanged(this, 188 DctConstants.EVENT_DATA_STATE_CHANGED, null); 189 mPhone.getCallTracker().registerForVoiceCallEnded (this, 190 DctConstants.EVENT_VOICE_CALL_ENDED, null); 191 mPhone.getCallTracker().registerForVoiceCallStarted (this, 192 DctConstants.EVENT_VOICE_CALL_STARTED, null); 193 mPhone.getServiceStateTracker().registerForDataConnectionAttached(this, 194 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); 195 mPhone.getServiceStateTracker().registerForDataConnectionDetached(this, 196 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); 197 mPhone.getServiceStateTracker().registerForDataRoamingOn(this, 198 DctConstants.EVENT_ROAMING_ON, null); 199 mPhone.getServiceStateTracker().registerForDataRoamingOff(this, 200 DctConstants.EVENT_ROAMING_OFF, null); 201 mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, 202 DctConstants.EVENT_PS_RESTRICT_ENABLED, null); 203 mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, 204 DctConstants.EVENT_PS_RESTRICT_DISABLED, null); 205 // SubscriptionManager.registerForDdsSwitch(this, 206 // DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null); 207 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this, 208 DctConstants.EVENT_DATA_RAT_CHANGED, null); 209 } 210 @Override 211 public void dispose() { 212 if (DBG) log("DcTracker.dispose"); 213 214 if (mProvisionBroadcastReceiver != null) { 215 mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); 216 mProvisionBroadcastReceiver = null; 217 } 218 if (mProvisioningSpinner != null) { 219 mProvisioningSpinner.dismiss(); 220 mProvisioningSpinner = null; 221 } 222 223 cleanUpAllConnections(true, null); 224 225 super.dispose(); 226 227 mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); 228 mApnContexts.clear(); 229 mPrioritySortedApnContexts.clear(); 230 231 destroyDataConnections(); 232 } 233 protected void unregisterForAllEvents() { 234 //Unregister for all events 235 mPhone.mCi.unregisterForAvailable(this); 236 mPhone.mCi.unregisterForOffOrNotAvailable(this); 237 IccRecords r = mIccRecords.get(); 238 if (r != null) { 239 r.unregisterForRecordsLoaded(this); 240 mIccRecords.set(null); 241 } 242 mPhone.mCi.unregisterForDataNetworkStateChanged(this); 243 mPhone.getCallTracker().unregisterForVoiceCallEnded(this); 244 mPhone.getCallTracker().unregisterForVoiceCallStarted(this); 245 mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this); 246 mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this); 247 mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); 248 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 249 mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); 250 mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); 251 //SubscriptionManager.unregisterForDdsSwitch(this); 252 } 253 254 @Override 255 public void incApnRefCount(String name) { 256 ApnContext apnContext = mApnContexts.get(name); 257 if (apnContext != null) { 258 apnContext.incRefCount(); 259 } 260 } 261 262 @Override 263 public void decApnRefCount(String name) { 264 ApnContext apnContext = mApnContexts.get(name); 265 if (apnContext != null) { 266 apnContext.decRefCount(); 267 } 268 } 269 270 @Override 271 public boolean isApnSupported(String name) { 272 if (name == null) { 273 loge("isApnSupported: name=null"); 274 return false; 275 } 276 ApnContext apnContext = mApnContexts.get(name); 277 if (apnContext == null) { 278 loge("Request for unsupported mobile name: " + name); 279 return false; 280 } 281 return true; 282 } 283 284 @Override 285 public int getApnPriority(String name) { 286 ApnContext apnContext = mApnContexts.get(name); 287 if (apnContext == null) { 288 loge("Request for unsupported mobile name: " + name); 289 } 290 return apnContext.priority; 291 } 292 293 // Turn telephony radio on or off. 294 private void setRadio(boolean on) { 295 final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 296 try { 297 phone.setRadio(on); 298 } catch (Exception e) { 299 // Ignore. 300 } 301 } 302 303 // Class to handle Intent dispatched with user selects the "Sign-in to network" 304 // notification. 305 private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { 306 private final String mNetworkOperator; 307 // Mobile provisioning URL. Valid while provisioning notification is up. 308 // Set prior to notification being posted as URL contains ICCID which 309 // disappears when radio is off (which is the case when notification is up). 310 private final String mProvisionUrl; 311 312 public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { 313 mNetworkOperator = networkOperator; 314 mProvisionUrl = provisionUrl; 315 } 316 317 private void setEnableFailFastMobileData(int enabled) { 318 sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); 319 } 320 321 private void enableMobileProvisioning() { 322 final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); 323 msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl)); 324 sendMessage(msg); 325 } 326 327 @Override 328 public void onReceive(Context context, Intent intent) { 329 // Turning back on the radio can take time on the order of a minute, so show user a 330 // spinner so they know something is going on. 331 mProvisioningSpinner = new ProgressDialog(context); 332 mProvisioningSpinner.setTitle(mNetworkOperator); 333 mProvisioningSpinner.setMessage( 334 // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. 335 context.getText(com.android.internal.R.string.media_route_status_connecting)); 336 mProvisioningSpinner.setIndeterminate(true); 337 mProvisioningSpinner.setCancelable(true); 338 // Allow non-Activity Service Context to create a View. 339 mProvisioningSpinner.getWindow().setType( 340 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 341 mProvisioningSpinner.show(); 342 // After timeout, hide spinner so user can at least use their device. 343 // TODO: Indicate to user that it is taking an unusually long time to connect? 344 sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, 345 mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); 346 // This code is almost identical to the old 347 // ConnectivityService.handleMobileProvisioningAction code. 348 setRadio(true); 349 setEnableFailFastMobileData(DctConstants.ENABLED); 350 enableMobileProvisioning(); 351 } 352 } 353 354 @Override 355 public boolean isApnTypeActive(String type) { 356 ApnContext apnContext = mApnContexts.get(type); 357 if (apnContext == null) return false; 358 359 return (apnContext.getDcAc() != null); 360 } 361 362 @Override 363 public boolean isDataPossible(String apnType) { 364 ApnContext apnContext = mApnContexts.get(apnType); 365 if (apnContext == null) { 366 return false; 367 } 368 boolean apnContextIsEnabled = apnContext.isEnabled(); 369 DctConstants.State apnContextState = apnContext.getState(); 370 boolean apnTypePossible = !(apnContextIsEnabled && 371 (apnContextState == DctConstants.State.FAILED)); 372 boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); 373 // Set the emergency APN availability status as TRUE irrespective of conditions checked in 374 // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc. 375 boolean dataAllowed = isEmergencyApn || isDataAllowed(); 376 boolean possible = dataAllowed && apnTypePossible; 377 378 if (VDBG) { 379 log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " + 380 "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s", 381 apnType, possible, dataAllowed, apnTypePossible, 382 apnContextIsEnabled, apnContextState)); 383 } 384 return possible; 385 } 386 387 @Override 388 protected void finalize() { 389 if(DBG) log("finalize"); 390 } 391 392 protected void supplyMessenger() { 393 ConnectivityManager cm = (ConnectivityManager)mPhone.getContext().getSystemService( 394 Context.CONNECTIVITY_SERVICE); 395 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE, new Messenger(this)); 396 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_MMS, new Messenger(this)); 397 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_SUPL, new Messenger(this)); 398 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_DUN, new Messenger(this)); 399 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_HIPRI, new Messenger(this)); 400 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_FOTA, new Messenger(this)); 401 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_IMS, new Messenger(this)); 402 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_CBS, new Messenger(this)); 403 cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_EMERGENCY, new Messenger(this)); 404 } 405 406 private ApnContext addApnContext(String type, NetworkConfig networkConfig) { 407 ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG, networkConfig, 408 this); 409 mApnContexts.put(type, apnContext); 410 mPrioritySortedApnContexts.add(apnContext); 411 return apnContext; 412 } 413 414 protected void initApnContexts() { 415 log("initApnContexts: E"); 416 // Load device network attributes from resources 417 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray( 418 com.android.internal.R.array.networkAttributes); 419 for (String networkConfigString : networkConfigStrings) { 420 NetworkConfig networkConfig = new NetworkConfig(networkConfigString); 421 ApnContext apnContext = null; 422 423 switch (networkConfig.type) { 424 case ConnectivityManager.TYPE_MOBILE: 425 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig); 426 break; 427 case ConnectivityManager.TYPE_MOBILE_MMS: 428 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig); 429 break; 430 case ConnectivityManager.TYPE_MOBILE_SUPL: 431 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig); 432 break; 433 case ConnectivityManager.TYPE_MOBILE_DUN: 434 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig); 435 break; 436 case ConnectivityManager.TYPE_MOBILE_HIPRI: 437 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig); 438 break; 439 case ConnectivityManager.TYPE_MOBILE_FOTA: 440 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig); 441 break; 442 case ConnectivityManager.TYPE_MOBILE_IMS: 443 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig); 444 break; 445 case ConnectivityManager.TYPE_MOBILE_CBS: 446 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig); 447 break; 448 case ConnectivityManager.TYPE_MOBILE_IA: 449 apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig); 450 break; 451 case ConnectivityManager.TYPE_MOBILE_EMERGENCY: 452 apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig); 453 break; 454 default: 455 log("initApnContexts: skipping unknown type=" + networkConfig.type); 456 continue; 457 } 458 log("initApnContexts: apnContext=" + apnContext); 459 } 460 log("initApnContexts: X mApnContexts=" + mApnContexts); 461 } 462 463 @Override 464 public LinkProperties getLinkProperties(String apnType) { 465 ApnContext apnContext = mApnContexts.get(apnType); 466 if (apnContext != null) { 467 DcAsyncChannel dcac = apnContext.getDcAc(); 468 if (dcac != null) { 469 if (DBG) log("return link properites for " + apnType); 470 return dcac.getLinkPropertiesSync(); 471 } 472 } 473 if (DBG) log("return new LinkProperties"); 474 return new LinkProperties(); 475 } 476 477 @Override 478 public NetworkCapabilities getNetworkCapabilities(String apnType) { 479 ApnContext apnContext = mApnContexts.get(apnType); 480 if (apnContext!=null) { 481 DcAsyncChannel dataConnectionAc = apnContext.getDcAc(); 482 if (dataConnectionAc != null) { 483 if (DBG) { 484 log("get active pdp is not null, return NetworkCapabilities for " + apnType); 485 } 486 return dataConnectionAc.getNetworkCapabilitiesSync(); 487 } 488 } 489 if (DBG) log("return new NetworkCapabilities"); 490 return new NetworkCapabilities(); 491 } 492 493 @Override 494 // Return all active apn types 495 public String[] getActiveApnTypes() { 496 if (DBG) log("get all active apn types"); 497 ArrayList<String> result = new ArrayList<String>(); 498 499 for (ApnContext apnContext : mApnContexts.values()) { 500 if (mAttached.get() && apnContext.isReady()) { 501 result.add(apnContext.getApnType()); 502 } 503 } 504 505 return result.toArray(new String[0]); 506 } 507 508 @Override 509 // Return active apn of specific apn type 510 public String getActiveApnString(String apnType) { 511 if (VDBG) log( "get active apn string for type:" + apnType); 512 ApnContext apnContext = mApnContexts.get(apnType); 513 if (apnContext != null) { 514 ApnSetting apnSetting = apnContext.getApnSetting(); 515 if (apnSetting != null) { 516 return apnSetting.apn; 517 } 518 } 519 return null; 520 } 521 522 @Override 523 public boolean isApnTypeEnabled(String apnType) { 524 ApnContext apnContext = mApnContexts.get(apnType); 525 if (apnContext == null) { 526 return false; 527 } 528 return apnContext.isEnabled(); 529 } 530 531 @Override 532 protected void setState(DctConstants.State s) { 533 if (DBG) log("setState should not be used in GSM" + s); 534 } 535 536 // Return state of specific apn type 537 @Override 538 public DctConstants.State getState(String apnType) { 539 ApnContext apnContext = mApnContexts.get(apnType); 540 if (apnContext != null) { 541 return apnContext.getState(); 542 } 543 return DctConstants.State.FAILED; 544 } 545 546 // Return if apn type is a provisioning apn. 547 @Override 548 protected boolean isProvisioningApn(String apnType) { 549 ApnContext apnContext = mApnContexts.get(apnType); 550 if (apnContext != null) { 551 return apnContext.isProvisioningApn(); 552 } 553 return false; 554 } 555 556 // Return state of overall 557 @Override 558 public DctConstants.State getOverallState() { 559 boolean isConnecting = false; 560 boolean isFailed = true; // All enabled Apns should be FAILED. 561 boolean isAnyEnabled = false; 562 563 for (ApnContext apnContext : mApnContexts.values()) { 564 if (apnContext.isEnabled()) { 565 isAnyEnabled = true; 566 switch (apnContext.getState()) { 567 case CONNECTED: 568 case DISCONNECTING: 569 if (DBG) log("overall state is CONNECTED"); 570 return DctConstants.State.CONNECTED; 571 case RETRYING: 572 case CONNECTING: 573 isConnecting = true; 574 isFailed = false; 575 break; 576 case IDLE: 577 case SCANNING: 578 isFailed = false; 579 break; 580 default: 581 isAnyEnabled = true; 582 break; 583 } 584 } 585 } 586 587 if (!isAnyEnabled) { // Nothing enabled. return IDLE. 588 if (DBG) log( "overall state is IDLE"); 589 return DctConstants.State.IDLE; 590 } 591 592 if (isConnecting) { 593 if (DBG) log( "overall state is CONNECTING"); 594 return DctConstants.State.CONNECTING; 595 } else if (!isFailed) { 596 if (DBG) log( "overall state is IDLE"); 597 return DctConstants.State.IDLE; 598 } else { 599 if (DBG) log( "overall state is FAILED"); 600 return DctConstants.State.FAILED; 601 } 602 } 603 604 @Override 605 protected boolean isApnTypeAvailable(String type) { 606 if (type.equals(PhoneConstants.APN_TYPE_DUN) && fetchDunApn() != null) { 607 return true; 608 } 609 610 if (mAllApnSettings != null) { 611 for (ApnSetting apn : mAllApnSettings) { 612 if (apn.canHandleType(type)) { 613 return true; 614 } 615 } 616 } 617 return false; 618 } 619 620 /** 621 * Report on whether data connectivity is enabled for any APN. 622 * @return {@code false} if data connectivity has been explicitly disabled, 623 * {@code true} otherwise. 624 */ 625 @Override 626 public boolean getAnyDataEnabled() { 627 synchronized (mDataEnabledLock) { 628 if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false; 629 for (ApnContext apnContext : mApnContexts.values()) { 630 // Make sure we don't have a context that is going down 631 // and is explicitly disabled. 632 if (isDataAllowed(apnContext)) { 633 return true; 634 } 635 } 636 return false; 637 } 638 } 639 640 public boolean getAnyDataEnabled(boolean checkUserDataEnabled) { 641 synchronized (mDataEnabledLock) { 642 if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled) 643 && (!checkUserDataEnabled || sPolicyDataEnabled))) 644 return false; 645 646 for (ApnContext apnContext : mApnContexts.values()) { 647 // Make sure we dont have a context that going down 648 // and is explicitly disabled. 649 if (isDataAllowed(apnContext)) { 650 return true; 651 } 652 } 653 return false; 654 } 655 } 656 657 private boolean isDataAllowed(ApnContext apnContext) { 658 return apnContext.isReady() && isDataAllowed(); 659 } 660 661 //****** Called from ServiceStateTracker 662 /** 663 * Invoked when ServiceStateTracker observes a transition from GPRS 664 * attach to detach. 665 */ 666 protected void onDataConnectionDetached() { 667 /* 668 * We presently believe it is unnecessary to tear down the PDP context 669 * when GPRS detaches, but we should stop the network polling. 670 */ 671 if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); 672 stopNetStatPoll(); 673 stopDataStallAlarm(); 674 notifyDataConnection(Phone.REASON_DATA_DETACHED); 675 mAttached.set(false); 676 } 677 678 private void onDataConnectionAttached() { 679 if (DBG) log("onDataConnectionAttached"); 680 mAttached.set(true); 681 if (getOverallState() == DctConstants.State.CONNECTED) { 682 if (DBG) log("onDataConnectionAttached: start polling notify attached"); 683 startNetStatPoll(); 684 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 685 notifyDataConnection(Phone.REASON_DATA_ATTACHED); 686 } else { 687 // update APN availability so that APN can be enabled. 688 notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED); 689 } 690 if (mAutoAttachOnCreationConfig) { 691 mAutoAttachOnCreation = true; 692 } 693 setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED); 694 } 695 696 @Override 697 protected boolean isDataAllowed() { 698 final boolean internalDataEnabled; 699 synchronized (mDataEnabledLock) { 700 internalDataEnabled = mInternalDataEnabled; 701 } 702 703 boolean attachedState = mAttached.get(); 704 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); 705 IccRecords r = mIccRecords.get(); 706 boolean recordsLoaded = false; 707 if (r != null) { 708 recordsLoaded = r.getRecordsLoaded(); 709 if (DBG) log("isDataAllowed getRecordsLoaded=" + recordsLoaded); 710 } 711 712 //FIXME always attach 713 boolean psRestricted = mIsPsRestricted; 714 int phoneNum = TelephonyManager.getDefault().getPhoneCount(); 715 if (phoneNum > 1) { 716 attachedState = true; 717 psRestricted = false; 718 } 719 int dataSub = SubscriptionManager.getDefaultDataSubId(); 720 boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub); 721 PhoneConstants.State state = PhoneConstants.State.IDLE; 722 if (mPhone.getCallTracker() != null) { 723 state = mPhone.getCallTracker().getState(); 724 } 725 boolean allowed = 726 (attachedState || mAutoAttachOnCreation) && 727 recordsLoaded && 728 (state == PhoneConstants.State.IDLE || 729 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) && 730 internalDataEnabled && 731 defaultDataSelected && 732 (!mPhone.getServiceState().getDataRoaming() || getDataOnRoamingEnabled()) && 733 //!mIsPsRestricted && 734 !psRestricted && 735 desiredPowerState; 736 if (!allowed && DBG) { 737 String reason = ""; 738 if (!(attachedState || mAutoAttachOnCreation)) { 739 reason += " - Attached= " + attachedState; 740 } 741 if (!recordsLoaded) reason += " - SIM not loaded"; 742 if (state != PhoneConstants.State.IDLE && 743 !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 744 reason += " - PhoneState= " + state; 745 reason += " - Concurrent voice and data not allowed"; 746 } 747 if (!internalDataEnabled) reason += " - mInternalDataEnabled= false"; 748 if (!defaultDataSelected) reason += " - defaultDataSelected= false"; 749 if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) { 750 reason += " - Roaming and data roaming not enabled"; 751 } 752 if (mIsPsRestricted) reason += " - mIsPsRestricted= true"; 753 if (!desiredPowerState) reason += " - desiredPowerState= false"; 754 if (DBG) log("isDataAllowed: not allowed due to" + reason); 755 } 756 return allowed; 757 } 758 759 // arg for setupDataOnConnectableApns 760 private enum RetryFailures { 761 // retry failed networks always (the old default) 762 ALWAYS, 763 // retry only when a substantial change has occured. Either: 764 // 1) we were restricted by voice/data concurrency and aren't anymore 765 // 2) our apn list has change 766 ONLY_ON_CHANGE 767 }; 768 769 private void setupDataOnConnectableApns(String reason) { 770 setupDataOnConnectableApns(reason, RetryFailures.ALWAYS); 771 } 772 773 private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) { 774 if (DBG) log("setupDataOnConnectableApns: " + reason); 775 ArrayList<ApnSetting> waitingApns = null; 776 777 for (ApnContext apnContext : mPrioritySortedApnContexts) { 778 if (DBG) log("setupDataOnConnectableApns: apnContext " + apnContext); 779 if (apnContext.getState() == DctConstants.State.FAILED) { 780 if (retryFailures == RetryFailures.ALWAYS) { 781 apnContext.setState(DctConstants.State.IDLE); 782 } else if (apnContext.isConcurrentVoiceAndDataAllowed() == false && 783 mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { 784 // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed 785 apnContext.setState(DctConstants.State.IDLE); 786 } else { 787 // RetryFailures.ONLY_ON_CHANGE - check if the apns have changed 788 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 789 ArrayList<ApnSetting> originalApns = apnContext.getOriginalWaitingApns(); 790 if (originalApns != null && originalApns.isEmpty() == false) { 791 waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech); 792 if (originalApns.size() != waitingApns.size() || 793 originalApns.containsAll(waitingApns) == false) { 794 apnContext.setState(DctConstants.State.IDLE); 795 } 796 } 797 } 798 } 799 if (apnContext.isConnectable()) { 800 log("setupDataOnConnectableApns: isConnectable() call trySetupData"); 801 apnContext.setReason(reason); 802 trySetupData(apnContext, waitingApns); 803 } 804 } 805 } 806 807 private boolean trySetupData(ApnContext apnContext) { 808 return trySetupData(apnContext, null); 809 } 810 811 private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) { 812 if (DBG) { 813 log("trySetupData for type:" + apnContext.getApnType() + 814 " due to " + apnContext.getReason() + " apnContext=" + apnContext); 815 log("trySetupData with mIsPsRestricted=" + mIsPsRestricted); 816 } 817 818 if (mPhone.getSimulatedRadioControl() != null) { 819 // Assume data is connected on the simulator 820 // FIXME this can be improved 821 apnContext.setState(DctConstants.State.CONNECTED); 822 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 823 824 log("trySetupData: X We're on the simulator; assuming connected retValue=true"); 825 return true; 826 } 827 828 // Allow SETUP_DATA request for E-APN to be completed during emergency call 829 // and MOBILE DATA On/Off cases as well. 830 boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY); 831 final ServiceStateTracker sst = mPhone.getServiceStateTracker(); 832 boolean desiredPowerState = sst.getDesiredPowerState(); 833 boolean checkUserDataEnabled = 834 !(apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)); 835 836 if (apnContext.isConnectable() && (isEmergencyApn || 837 (isDataAllowed(apnContext) && 838 getAnyDataEnabled(checkUserDataEnabled) && !isEmergency()))) { 839 if (apnContext.getState() == DctConstants.State.FAILED) { 840 if (DBG) log("trySetupData: make a FAILED ApnContext IDLE so its reusable"); 841 apnContext.setState(DctConstants.State.IDLE); 842 } 843 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 844 apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed()); 845 if (apnContext.getState() == DctConstants.State.IDLE) { 846 if (waitingApns == null) { 847 waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech); 848 } 849 if (waitingApns.isEmpty()) { 850 notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext); 851 notifyOffApnsOfAvailability(apnContext.getReason()); 852 if (DBG) log("trySetupData: X No APN found retValue=false"); 853 return false; 854 } else { 855 apnContext.setWaitingApns(waitingApns); 856 if (DBG) { 857 log ("trySetupData: Create from mAllApnSettings : " 858 + apnListToString(mAllApnSettings)); 859 } 860 } 861 } 862 863 if (DBG) { 864 log("trySetupData: call setupData, waitingApns : " 865 + apnListToString(apnContext.getWaitingApns())); 866 } 867 boolean retValue = setupData(apnContext, radioTech); 868 notifyOffApnsOfAvailability(apnContext.getReason()); 869 870 if (DBG) log("trySetupData: X retValue=" + retValue); 871 return retValue; 872 } else { 873 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT) 874 && apnContext.isConnectable()) { 875 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 876 } 877 notifyOffApnsOfAvailability(apnContext.getReason()); 878 if (DBG) log ("trySetupData: X apnContext not 'ready' retValue=false"); 879 return false; 880 } 881 } 882 883 @Override 884 // Disabled apn's still need avail/unavail notificiations - send them out 885 protected void notifyOffApnsOfAvailability(String reason) { 886 for (ApnContext apnContext : mApnContexts.values()) { 887 if (!mAttached.get() || !apnContext.isReady()) { 888 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType()); 889 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(), 890 apnContext.getApnType(), 891 PhoneConstants.DataState.DISCONNECTED); 892 } else { 893 if (VDBG) { 894 log("notifyOffApnsOfAvailability skipped apn due to attached && isReady " + 895 apnContext.toString()); 896 } 897 } 898 } 899 } 900 901 /** 902 * If tearDown is true, this only tears down a CONNECTED session. Presently, 903 * there is no mechanism for abandoning an CONNECTING session, 904 * but would likely involve cancelling pending async requests or 905 * setting a flag or new state to ignore them when they came in 906 * @param tearDown true if the underlying DataConnection should be 907 * disconnected. 908 * @param reason reason for the clean up. 909 * @return boolean - true if we did cleanup any connections, false if they 910 * were already all disconnected. 911 */ 912 protected boolean cleanUpAllConnections(boolean tearDown, String reason) { 913 if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason); 914 boolean didDisconnect = false; 915 boolean specificdisable = false; 916 917 if (!TextUtils.isEmpty(reason)) { 918 specificdisable = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED); 919 } 920 921 for (ApnContext apnContext : mApnContexts.values()) { 922 if (apnContext.isDisconnected() == false) didDisconnect = true; 923 if (specificdisable) { 924 if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)) { 925 if (DBG) log("ApnConextType: " + apnContext.getApnType()); 926 apnContext.setReason(reason); 927 cleanUpConnection(tearDown, apnContext); 928 } 929 } else { 930 // TODO - only do cleanup if not disconnected 931 apnContext.setReason(reason); 932 cleanUpConnection(tearDown, apnContext); 933 } 934 } 935 936 stopNetStatPoll(); 937 stopDataStallAlarm(); 938 939 // TODO: Do we need mRequestedApnType? 940 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 941 942 log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount); 943 if (tearDown && mDisconnectPendingCount == 0) { 944 notifyDataDisconnectComplete(); 945 notifyAllDataDisconnected(); 946 } 947 948 return didDisconnect; 949 } 950 951 /** 952 * Cleanup all connections. 953 * 954 * TODO: Cleanup only a specified connection passed as a parameter. 955 * Also, make sure when you clean up a conn, if it is last apply 956 * logic as though it is cleanupAllConnections 957 * 958 * @param cause for the clean up. 959 */ 960 961 @Override 962 protected void onCleanUpAllConnections(String cause) { 963 cleanUpAllConnections(true, cause); 964 } 965 966 protected void cleanUpConnection(boolean tearDown, ApnContext apnContext) { 967 968 if (apnContext == null) { 969 if (DBG) log("cleanUpConnection: apn context is null"); 970 return; 971 } 972 973 DcAsyncChannel dcac = apnContext.getDcAc(); 974 if (DBG) { 975 log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() + 976 " apnContext=" + apnContext); 977 } 978 if (tearDown) { 979 if (apnContext.isDisconnected()) { 980 // The request is tearDown and but ApnContext is not connected. 981 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC. 982 apnContext.setState(DctConstants.State.IDLE); 983 if (!apnContext.isReady()) { 984 if (dcac != null) { 985 if (DBG) { 986 log("cleanUpConnection: teardown, disconnected, !ready apnContext=" 987 + apnContext); 988 } 989 dcac.tearDown(apnContext, "", null); 990 } 991 apnContext.setDataConnectionAc(null); 992 } 993 } else { 994 // Connection is still there. Try to clean up. 995 if (dcac != null) { 996 if (apnContext.getState() != DctConstants.State.DISCONNECTING) { 997 boolean disconnectAll = false; 998 if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) { 999 // CAF_MSIM is this below condition required. 1000 // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) { 1001 if (teardownForDun()) { 1002 if (DBG) { 1003 log("cleanUpConnection: disconnectAll DUN connection"); 1004 } 1005 // we need to tear it down - we brought it up just for dun and 1006 // other people are camped on it and now dun is done. We need 1007 // to stop using it and let the normal apn list get used to find 1008 // connections for the remaining desired connections 1009 disconnectAll = true; 1010 } 1011 } 1012 if (DBG) { 1013 log("cleanUpConnection: tearing down" + (disconnectAll ? " all" :"") 1014 + "apnContext=" + apnContext); 1015 } 1016 Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext); 1017 if (disconnectAll) { 1018 apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg); 1019 } else { 1020 apnContext.getDcAc() 1021 .tearDown(apnContext, apnContext.getReason(), msg); 1022 } 1023 apnContext.setState(DctConstants.State.DISCONNECTING); 1024 mDisconnectPendingCount++; 1025 } 1026 } else { 1027 // apn is connected but no reference to dcac. 1028 // Should not be happen, but reset the state in case. 1029 apnContext.setState(DctConstants.State.IDLE); 1030 mPhone.notifyDataConnection(apnContext.getReason(), 1031 apnContext.getApnType()); 1032 } 1033 } 1034 } else { 1035 // force clean up the data connection. 1036 if (dcac != null) dcac.reqReset(); 1037 apnContext.setState(DctConstants.State.IDLE); 1038 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1039 apnContext.setDataConnectionAc(null); 1040 } 1041 1042 // Make sure reconnection alarm is cleaned up if there is no ApnContext 1043 // associated to the connection. 1044 if (dcac != null) { 1045 cancelReconnectAlarm(apnContext); 1046 } 1047 if (DBG) { 1048 log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() + 1049 " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc()); 1050 } 1051 } 1052 1053 /** 1054 * Determine if DUN connection is special and we need to teardown on start/stop 1055 */ 1056 private boolean teardownForDun() { 1057 // CDMA always needs to do this the profile id is correct 1058 final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology(); 1059 if (ServiceState.isCdma(rilRat)) return true; 1060 1061 return (fetchDunApn() != null); 1062 } 1063 1064 /** 1065 * Cancels the alarm associated with apnContext. 1066 * 1067 * @param apnContext on which the alarm should be stopped. 1068 */ 1069 private void cancelReconnectAlarm(ApnContext apnContext) { 1070 if (apnContext == null) return; 1071 1072 PendingIntent intent = apnContext.getReconnectIntent(); 1073 1074 if (intent != null) { 1075 AlarmManager am = 1076 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1077 am.cancel(intent); 1078 apnContext.setReconnectIntent(null); 1079 } 1080 } 1081 1082 /** 1083 * @param types comma delimited list of APN types 1084 * @return array of APN types 1085 */ 1086 private String[] parseTypes(String types) { 1087 String[] result; 1088 // If unset, set to DEFAULT. 1089 if (types == null || types.equals("")) { 1090 result = new String[1]; 1091 result[0] = PhoneConstants.APN_TYPE_ALL; 1092 } else { 1093 result = types.split(","); 1094 } 1095 return result; 1096 } 1097 1098 private boolean imsiMatches(String imsiDB, String imsiSIM) { 1099 // Note: imsiDB value has digit number or 'x' character for seperating USIM information 1100 // for MVNO operator. And then digit number is matched at same order and 'x' character 1101 // could replace by any digit number. 1102 // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator, 1103 // that means first 6 digits, 8th and 9th digit 1104 // should be set in USIM for GG Operator. 1105 int len = imsiDB.length(); 1106 int idxCompare = 0; 1107 1108 if (len <= 0) return false; 1109 if (len > imsiSIM.length()) return false; 1110 1111 for (int idx=0; idx<len; idx++) { 1112 char c = imsiDB.charAt(idx); 1113 if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) { 1114 continue; 1115 } else { 1116 return false; 1117 } 1118 } 1119 return true; 1120 } 1121 1122 @Override 1123 protected boolean mvnoMatches(IccRecords r, String mvnoType, String mvnoMatchData) { 1124 if (mvnoType.equalsIgnoreCase("spn")) { 1125 if ((r.getServiceProviderName() != null) && 1126 r.getServiceProviderName().equalsIgnoreCase(mvnoMatchData)) { 1127 return true; 1128 } 1129 } else if (mvnoType.equalsIgnoreCase("imsi")) { 1130 String imsiSIM = r.getIMSI(); 1131 if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) { 1132 return true; 1133 } 1134 } else if (mvnoType.equalsIgnoreCase("gid")) { 1135 String gid1 = r.getGid1(); 1136 int mvno_match_data_length = mvnoMatchData.length(); 1137 if ((gid1 != null) && (gid1.length() >= mvno_match_data_length) && 1138 gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) { 1139 return true; 1140 } 1141 } 1142 return false; 1143 } 1144 1145 @Override 1146 protected boolean isPermanentFail(DcFailCause dcFailCause) { 1147 return (dcFailCause.isPermanentFail() && 1148 (mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST)); 1149 } 1150 1151 private ApnSetting makeApnSetting(Cursor cursor) { 1152 String[] types = parseTypes( 1153 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE))); 1154 ApnSetting apn = new ApnSetting( 1155 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)), 1156 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)), 1157 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)), 1158 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)), 1159 NetworkUtils.trimV4AddrZeros( 1160 cursor.getString( 1161 cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))), 1162 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)), 1163 NetworkUtils.trimV4AddrZeros( 1164 cursor.getString( 1165 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))), 1166 NetworkUtils.trimV4AddrZeros( 1167 cursor.getString( 1168 cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))), 1169 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)), 1170 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)), 1171 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)), 1172 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)), 1173 types, 1174 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)), 1175 cursor.getString(cursor.getColumnIndexOrThrow( 1176 Telephony.Carriers.ROAMING_PROTOCOL)), 1177 cursor.getInt(cursor.getColumnIndexOrThrow( 1178 Telephony.Carriers.CARRIER_ENABLED)) == 1, 1179 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)), 1180 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)), 1181 cursor.getInt(cursor.getColumnIndexOrThrow( 1182 Telephony.Carriers.MODEM_COGNITIVE)) == 1, 1183 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)), 1184 cursor.getInt(cursor.getColumnIndexOrThrow( 1185 Telephony.Carriers.WAIT_TIME)), 1186 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)), 1187 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)), 1188 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE)), 1189 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA))); 1190 return apn; 1191 } 1192 1193 private ArrayList<ApnSetting> createApnList(Cursor cursor) { 1194 ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>(); 1195 ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>(); 1196 IccRecords r = mIccRecords.get(); 1197 1198 if (cursor.moveToFirst()) { 1199 do { 1200 ApnSetting apn = makeApnSetting(cursor); 1201 if (apn == null) { 1202 continue; 1203 } 1204 1205 if (apn.hasMvnoParams()) { 1206 if (r != null && mvnoMatches(r, apn.mvnoType, apn.mvnoMatchData)) { 1207 mvnoApns.add(apn); 1208 } 1209 } else { 1210 mnoApns.add(apn); 1211 } 1212 } while (cursor.moveToNext()); 1213 } 1214 1215 ArrayList<ApnSetting> result = mvnoApns.isEmpty() ? mnoApns : mvnoApns; 1216 if (DBG) log("createApnList: X result=" + result); 1217 return result; 1218 } 1219 1220 private boolean dataConnectionNotInUse(DcAsyncChannel dcac) { 1221 if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac); 1222 for (ApnContext apnContext : mApnContexts.values()) { 1223 if (apnContext.getDcAc() == dcac) { 1224 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext); 1225 return false; 1226 } 1227 } 1228 // TODO: Fix retry handling so free DataConnections have empty apnlists. 1229 // Probably move retry handling into DataConnections and reduce complexity 1230 // of DCT. 1231 if (DBG) log("dataConnectionNotInUse: tearDownAll"); 1232 dcac.tearDownAll("No connection", null); 1233 if (DBG) log("dataConnectionNotInUse: not in use return true"); 1234 return true; 1235 } 1236 1237 private DcAsyncChannel findFreeDataConnection() { 1238 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 1239 if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) { 1240 if (DBG) { 1241 log("findFreeDataConnection: found free DataConnection=" + 1242 " dcac=" + dcac); 1243 } 1244 return dcac; 1245 } 1246 } 1247 log("findFreeDataConnection: NO free DataConnection"); 1248 return null; 1249 } 1250 1251 private boolean setupData(ApnContext apnContext, int radioTech) { 1252 if (DBG) log("setupData: apnContext=" + apnContext); 1253 ApnSetting apnSetting; 1254 DcAsyncChannel dcac = null; 1255 1256 apnSetting = apnContext.getNextWaitingApn(); 1257 if (apnSetting == null) { 1258 if (DBG) log("setupData: return for no apn found!"); 1259 return false; 1260 } 1261 1262 int profileId = apnSetting.profileId; 1263 if (profileId == 0) { 1264 profileId = getApnProfileID(apnContext.getApnType()); 1265 } 1266 1267 // On CDMA, if we're explicitly asking for DUN, we need have 1268 // a dun-profiled connection so we can't share an existing one 1269 // On GSM/LTE we can share existing apn connections provided they support 1270 // this type. 1271 if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN || 1272 teardownForDun() == false) { 1273 dcac = checkForCompatibleConnectedApnContext(apnContext); 1274 if (dcac != null) { 1275 // Get the dcacApnSetting for the connection we want to share. 1276 ApnSetting dcacApnSetting = dcac.getApnSettingSync(); 1277 if (dcacApnSetting != null) { 1278 // Setting is good, so use it. 1279 apnSetting = dcacApnSetting; 1280 } 1281 } 1282 } 1283 if (dcac == null) { 1284 if (isOnlySingleDcAllowed(radioTech)) { 1285 if (isHigherPriorityApnContextActive(apnContext)) { 1286 if (DBG) { 1287 log("setupData: Higher priority ApnContext active. Ignoring call"); 1288 } 1289 return false; 1290 } 1291 1292 // Only lower priority calls left. Disconnect them all in this single PDP case 1293 // so that we can bring up the requested higher priority call (once we receive 1294 // repsonse for deactivate request for the calls we are about to disconnect 1295 if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { 1296 // If any call actually requested to be disconnected, means we can't 1297 // bring up this connection yet as we need to wait for those data calls 1298 // to be disconnected. 1299 if (DBG) log("setupData: Some calls are disconnecting first. Wait and retry"); 1300 return false; 1301 } 1302 1303 // No other calls are active, so proceed 1304 if (DBG) log("setupData: Single pdp. Continue setting up data call."); 1305 } 1306 1307 dcac = findFreeDataConnection(); 1308 1309 if (dcac == null) { 1310 dcac = createDataConnection(); 1311 } 1312 1313 if (dcac == null) { 1314 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); 1315 return false; 1316 } 1317 } 1318 if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting); 1319 1320 apnContext.setDataConnectionAc(dcac); 1321 apnContext.setApnSetting(apnSetting); 1322 apnContext.setState(DctConstants.State.CONNECTING); 1323 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType()); 1324 1325 Message msg = obtainMessage(); 1326 msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; 1327 msg.obj = apnContext; 1328 dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, radioTech, mAutoAttachOnCreation, 1329 msg); 1330 1331 if (DBG) log("setupData: initing!"); 1332 return true; 1333 } 1334 1335 /** 1336 * Handles changes to the APN database. 1337 */ 1338 private void onApnChanged() { 1339 DctConstants.State overallState = getOverallState(); 1340 boolean isDisconnected = (overallState == DctConstants.State.IDLE || 1341 overallState == DctConstants.State.FAILED); 1342 1343 if (mPhone instanceof GSMPhone) { 1344 // The "current" may no longer be valid. MMS depends on this to send properly. TBD 1345 ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); 1346 } 1347 1348 // TODO: It'd be nice to only do this if the changed entrie(s) 1349 // match the current operator. 1350 if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); 1351 createAllApnList(); 1352 setInitialAttachApn(); 1353 cleanUpConnectionsOnUpdatedApns(!isDisconnected); 1354 1355 // FIXME: See bug 17426028 maybe no conditional is needed. 1356 if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubId()) { 1357 setupDataOnConnectableApns(Phone.REASON_APN_CHANGED); 1358 } 1359 } 1360 1361 /** 1362 * @param cid Connection id provided from RIL. 1363 * @return DataConnectionAc associated with specified cid. 1364 */ 1365 private DcAsyncChannel findDataConnectionAcByCid(int cid) { 1366 for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) { 1367 if (dcac.getCidSync() == cid) { 1368 return dcac; 1369 } 1370 } 1371 return null; 1372 } 1373 1374 // TODO: For multiple Active APNs not exactly sure how to do this. 1375 @Override 1376 protected void gotoIdleAndNotifyDataConnection(String reason) { 1377 if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); 1378 notifyDataConnection(reason); 1379 mActiveApn = null; 1380 } 1381 1382 /** 1383 * "Active" here means ApnContext isEnabled() and not in FAILED state 1384 * @param apnContext to compare with 1385 * @return true if higher priority active apn found 1386 */ 1387 private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { 1388 for (ApnContext otherContext : mPrioritySortedApnContexts) { 1389 if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; 1390 if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { 1391 return true; 1392 } 1393 } 1394 return false; 1395 } 1396 1397 /** 1398 * Reports if we support multiple connections or not. 1399 * This is a combination of factors, based on carrier and RAT. 1400 * @param rilRadioTech the RIL Radio Tech currently in use 1401 * @return true if only single DataConnection is allowed 1402 */ 1403 private boolean isOnlySingleDcAllowed(int rilRadioTech) { 1404 int[] singleDcRats = mPhone.getContext().getResources().getIntArray( 1405 com.android.internal.R.array.config_onlySingleDcAllowed); 1406 boolean onlySingleDcAllowed = false; 1407 if (Build.IS_DEBUGGABLE && 1408 SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { 1409 onlySingleDcAllowed = true; 1410 } 1411 if (singleDcRats != null) { 1412 for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) { 1413 if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true; 1414 } 1415 } 1416 1417 if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed); 1418 return onlySingleDcAllowed; 1419 } 1420 1421 @Override 1422 protected void restartRadio() { 1423 if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); 1424 cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF); 1425 mPhone.getServiceStateTracker().powerOffRadioSafely(this); 1426 /* Note: no need to call setRadioPower(true). Assuming the desired 1427 * radio power state is still ON (as tracked by ServiceStateTracker), 1428 * ServiceStateTracker will call setRadioPower when it receives the 1429 * RADIO_STATE_CHANGED notification for the power off. And if the 1430 * desired power state has changed in the interim, we don't want to 1431 * override it with an unconditional power on. 1432 */ 1433 1434 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0")); 1435 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); 1436 } 1437 1438 /** 1439 * Return true if data connection need to be setup after disconnected due to 1440 * reason. 1441 * 1442 * @param reason the reason why data is disconnected 1443 * @return true if try setup data connection is need for this reason 1444 */ 1445 private boolean retryAfterDisconnected(ApnContext apnContext) { 1446 boolean retry = true; 1447 String reason = apnContext.getReason(); 1448 1449 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || 1450 (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) 1451 && isHigherPriorityApnContextActive(apnContext))) { 1452 retry = false; 1453 } 1454 return retry; 1455 } 1456 1457 private void startAlarmForReconnect(int delay, ApnContext apnContext) { 1458 String apnType = apnContext.getApnType(); 1459 1460 Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType); 1461 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason()); 1462 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType); 1463 1464 // Get current sub id. 1465 int subId = SubscriptionManager.getDefaultDataSubId(); 1466 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1467 1468 if (DBG) { 1469 log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction() 1470 + " apn=" + apnContext); 1471 } 1472 1473 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, 1474 intent, PendingIntent.FLAG_UPDATE_CURRENT); 1475 apnContext.setReconnectIntent(alarmIntent); 1476 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1477 SystemClock.elapsedRealtime() + delay, alarmIntent); 1478 } 1479 1480 private void startAlarmForRestartTrySetup(int delay, ApnContext apnContext) { 1481 String apnType = apnContext.getApnType(); 1482 Intent intent = new Intent(INTENT_RESTART_TRYSETUP_ALARM + "." + apnType); 1483 intent.putExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE, apnType); 1484 1485 if (DBG) { 1486 log("startAlarmForRestartTrySetup: delay=" + delay + " action=" + intent.getAction() 1487 + " apn=" + apnContext); 1488 } 1489 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0, 1490 intent, PendingIntent.FLAG_UPDATE_CURRENT); 1491 apnContext.setReconnectIntent(alarmIntent); 1492 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1493 SystemClock.elapsedRealtime() + delay, alarmIntent); 1494 } 1495 1496 private void notifyNoData(DcFailCause lastFailCauseCode, 1497 ApnContext apnContext) { 1498 if (DBG) log( "notifyNoData: type=" + apnContext.getApnType()); 1499 if (isPermanentFail(lastFailCauseCode) 1500 && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) { 1501 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType()); 1502 } 1503 } 1504 1505 private void onRecordsLoaded() { 1506 if (DBG) log("onRecordsLoaded: createAllApnList"); 1507 mAutoAttachOnCreationConfig = mPhone.getContext().getResources() 1508 .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); 1509 1510 createAllApnList(); 1511 setInitialAttachApn(); 1512 if (mPhone.mCi.getRadioState().isOn()) { 1513 if (DBG) log("onRecordsLoaded: notifying data availability"); 1514 notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED); 1515 } 1516 setupDataOnConnectableApns(Phone.REASON_SIM_LOADED); 1517 } 1518 1519 @Override 1520 protected void onSetDependencyMet(String apnType, boolean met) { 1521 // don't allow users to tweak hipri to work around default dependency not met 1522 if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return; 1523 1524 ApnContext apnContext = mApnContexts.get(apnType); 1525 if (apnContext == null) { 1526 loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" + 1527 apnType + ", " + met + ")"); 1528 return; 1529 } 1530 applyNewState(apnContext, apnContext.isEnabled(), met); 1531 if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) { 1532 // tie actions on default to similar actions on HIPRI regarding dependencyMet 1533 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI); 1534 if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met); 1535 } 1536 } 1537 1538 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) { 1539 boolean cleanup = false; 1540 boolean trySetup = false; 1541 if (DBG) { 1542 log("applyNewState(" + apnContext.getApnType() + ", " + enabled + 1543 "(" + apnContext.isEnabled() + "), " + met + "(" + 1544 apnContext.getDependencyMet() +"))"); 1545 } 1546 if (apnContext.isReady()) { 1547 cleanup = true; 1548 if (enabled && met) { 1549 DctConstants.State state = apnContext.getState(); 1550 switch(state) { 1551 case CONNECTING: 1552 case SCANNING: 1553 case CONNECTED: 1554 case DISCONNECTING: 1555 // We're "READY" and active so just return 1556 if (DBG) log("applyNewState: 'ready' so return"); 1557 return; 1558 case IDLE: 1559 // fall through: this is unexpected but if it happens cleanup and try setup 1560 case FAILED: 1561 case RETRYING: { 1562 // We're "READY" but not active so disconnect (cleanup = true) and 1563 // connect (trySetup = true) to be sure we retry the connection. 1564 trySetup = true; 1565 apnContext.setReason(Phone.REASON_DATA_ENABLED); 1566 break; 1567 } 1568 } 1569 } else if (met) { 1570 apnContext.setReason(Phone.REASON_DATA_DISABLED); 1571 // If ConnectivityService has disabled this network, stop trying to bring 1572 // it up, but do not tear it down - ConnectivityService will do that 1573 // directly by talking with the DataConnection. 1574 // 1575 // This doesn't apply to DUN, however. Those connections have special 1576 // requirements from carriers and we need stop using them when the dun 1577 // request goes away. This applies to both CDMA and GSM because they both 1578 // can declare the DUN APN sharable by default traffic, thus still satisfying 1579 // those requests and not torn down organically. 1580 if (apnContext.getApnType() == PhoneConstants.APN_TYPE_DUN && teardownForDun()) { 1581 cleanup = true; 1582 } else { 1583 cleanup = false; 1584 } 1585 } else { 1586 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); 1587 } 1588 } else { 1589 if (enabled && met) { 1590 if (apnContext.isEnabled()) { 1591 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); 1592 } else { 1593 apnContext.setReason(Phone.REASON_DATA_ENABLED); 1594 } 1595 if (apnContext.getState() == DctConstants.State.FAILED) { 1596 apnContext.setState(DctConstants.State.IDLE); 1597 } 1598 trySetup = true; 1599 } 1600 } 1601 apnContext.setEnabled(enabled); 1602 apnContext.setDependencyMet(met); 1603 if (cleanup) cleanUpConnection(true, apnContext); 1604 if (trySetup) trySetupData(apnContext); 1605 } 1606 1607 private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) { 1608 String apnType = apnContext.getApnType(); 1609 ApnSetting dunSetting = null; 1610 1611 if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) { 1612 dunSetting = fetchDunApn(); 1613 } 1614 if (DBG) { 1615 log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext ); 1616 } 1617 1618 DcAsyncChannel potentialDcac = null; 1619 ApnContext potentialApnCtx = null; 1620 for (ApnContext curApnCtx : mApnContexts.values()) { 1621 DcAsyncChannel curDcac = curApnCtx.getDcAc(); 1622 log("curDcac: " + curDcac); 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 // query only enabled apn. 2243 // carrier_enabled : 1 means enabled apn, 0 disabled apn. 2244 // selection += " and carrier_enabled = 1"; 2245 if (DBG) log("createAllApnList: selection=" + selection); 2246 2247 Cursor cursor = mPhone.getContext().getContentResolver().query( 2248 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 2249 2250 if (cursor != null) { 2251 if (cursor.getCount() > 0) { 2252 mAllApnSettings = createApnList(cursor); 2253 } 2254 cursor.close(); 2255 } 2256 } 2257 2258 addEmergencyApnSetting(); 2259 2260 dedupeApnSettings(); 2261 2262 if (mAllApnSettings.isEmpty()) { 2263 if (DBG) log("createAllApnList: No APN found for carrier: " + operator); 2264 mPreferredApn = null; 2265 // TODO: What is the right behavior? 2266 //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN); 2267 } else { 2268 mPreferredApn = getPreferredApn(); 2269 if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { 2270 mPreferredApn = null; 2271 setPreferredApn(-1); 2272 } 2273 if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); 2274 } 2275 if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); 2276 2277 setDataProfilesAsNeeded(); 2278 } 2279 2280 private void dedupeApnSettings() { 2281 ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>(); 2282 2283 // coalesce APNs if they are similar enough to prevent 2284 // us from bringing up two data calls with the same interface 2285 int i = 0; 2286 while (i < mAllApnSettings.size() - 1) { 2287 ApnSetting first = mAllApnSettings.get(i); 2288 ApnSetting second = null; 2289 int j = i + 1; 2290 while (j < mAllApnSettings.size()) { 2291 second = mAllApnSettings.get(j); 2292 if (apnsSimilar(first, second)) { 2293 ApnSetting newApn = mergeApns(first, second); 2294 mAllApnSettings.set(i, newApn); 2295 first = newApn; 2296 mAllApnSettings.remove(j); 2297 } else { 2298 j++; 2299 } 2300 } 2301 i++; 2302 } 2303 } 2304 2305 //check whether the types of two APN same (even only one type of each APN is same) 2306 private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) { 2307 if(VDBG) { 2308 StringBuilder apnType1 = new StringBuilder(first.apn + ": "); 2309 for(int index1 = 0; index1 < first.types.length; index1++) { 2310 apnType1.append(first.types[index1]); 2311 apnType1.append(","); 2312 } 2313 2314 StringBuilder apnType2 = new StringBuilder(second.apn + ": "); 2315 for(int index1 = 0; index1 < second.types.length; index1++) { 2316 apnType2.append(second.types[index1]); 2317 apnType2.append(","); 2318 } 2319 log("APN1: is " + apnType1); 2320 log("APN2: is " + apnType2); 2321 } 2322 2323 for(int index1 = 0; index1 < first.types.length; index1++) { 2324 for(int index2 = 0; index2 < second.types.length; index2++) { 2325 if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) || 2326 second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) || 2327 first.types[index1].equals(second.types[index2])) { 2328 if(VDBG)log("apnTypeSameAny: return true"); 2329 return true; 2330 } 2331 } 2332 } 2333 2334 if(VDBG)log("apnTypeSameAny: return false"); 2335 return false; 2336 } 2337 2338 // Check if neither mention DUN and are substantially similar 2339 private boolean apnsSimilar(ApnSetting first, ApnSetting second) { 2340 return (first.canHandleType(PhoneConstants.APN_TYPE_DUN) == false && 2341 second.canHandleType(PhoneConstants.APN_TYPE_DUN) == false && 2342 Objects.equals(first.apn, second.apn) && 2343 !apnTypeSameAny(first, second) && 2344 xorEquals(first.proxy, second.proxy) && 2345 xorEquals(first.port, second.port) && 2346 first.carrierEnabled == second.carrierEnabled && 2347 first.bearer == second.bearer && 2348 first.profileId == second.profileId && 2349 Objects.equals(first.mvnoType, second.mvnoType) && 2350 Objects.equals(first.mvnoMatchData, second.mvnoMatchData) && 2351 xorEquals(first.mmsc, second.mmsc) && 2352 xorEquals(first.mmsProxy, second.mmsProxy) && 2353 xorEquals(first.mmsPort, second.mmsPort)); 2354 } 2355 2356 // equal or one is not specified 2357 private boolean xorEquals(String first, String second) { 2358 return (Objects.equals(first, second) || 2359 TextUtils.isEmpty(first) || 2360 TextUtils.isEmpty(second)); 2361 } 2362 2363 private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { 2364 ArrayList<String> resultTypes = new ArrayList<String>(); 2365 resultTypes.addAll(Arrays.asList(dest.types)); 2366 for (String srcType : src.types) { 2367 if (resultTypes.contains(srcType) == false) resultTypes.add(srcType); 2368 } 2369 String mmsc = (TextUtils.isEmpty(dest.mmsc) ? src.mmsc : dest.mmsc); 2370 String mmsProxy = (TextUtils.isEmpty(dest.mmsProxy) ? src.mmsProxy : dest.mmsProxy); 2371 String mmsPort = (TextUtils.isEmpty(dest.mmsPort) ? src.mmsPort : dest.mmsPort); 2372 String proxy = (TextUtils.isEmpty(dest.proxy) ? src.proxy : dest.proxy); 2373 String port = (TextUtils.isEmpty(dest.port) ? src.port : dest.port); 2374 String protocol = src.protocol.equals("IPV4V6") ? src.protocol : dest.protocol; 2375 String roamingProtocol = src.roamingProtocol.equals("IPV4V6") ? src.roamingProtocol : 2376 dest.roamingProtocol; 2377 2378 return new ApnSetting(dest.id, dest.numeric, dest.carrier, dest.apn, 2379 proxy, port, mmsc, mmsProxy, mmsPort, dest.user, dest.password, 2380 dest.authType, resultTypes.toArray(new String[0]), protocol, 2381 roamingProtocol, dest.carrierEnabled, dest.bearer, dest.profileId, 2382 (dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime, 2383 dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData); 2384 } 2385 2386 /** Return the DC AsyncChannel for the new data connection */ 2387 private DcAsyncChannel createDataConnection() { 2388 if (DBG) log("createDataConnection E"); 2389 2390 int id = mUniqueIdGenerator.getAndIncrement(); 2391 DataConnection conn = DataConnection.makeDataConnection(mPhone, id, 2392 this, mDcTesterFailBringUpAll, mDcc); 2393 mDataConnections.put(id, conn); 2394 DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG); 2395 int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler()); 2396 if (status == AsyncChannel.STATUS_SUCCESSFUL) { 2397 mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac); 2398 } else { 2399 loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status); 2400 } 2401 2402 if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn); 2403 return dcac; 2404 } 2405 2406 private void destroyDataConnections() { 2407 if(mDataConnections != null) { 2408 if (DBG) log("destroyDataConnections: clear mDataConnectionList"); 2409 mDataConnections.clear(); 2410 } else { 2411 if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); 2412 } 2413 } 2414 2415 /** 2416 * Build a list of APNs to be used to create PDP's. 2417 * 2418 * @param requestedApnType 2419 * @return waitingApns list to be used to create PDP 2420 * error when waitingApns.isEmpty() 2421 */ 2422 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) { 2423 if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); 2424 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); 2425 2426 if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) { 2427 ApnSetting dun = fetchDunApn(); 2428 if (dun != null) { 2429 apnList.add(dun); 2430 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); 2431 return apnList; 2432 } 2433 } 2434 2435 IccRecords r = mIccRecords.get(); 2436 String operator = (r != null) ? r.getOperatorNumeric() : ""; 2437 2438 // This is a workaround for a bug (7305641) where we don't failover to other 2439 // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to 2440 // failover to a provisioning APN, but once we've used their default data 2441 // connection we are locked to it for life. This change allows ATT devices 2442 // to say they don't want to use preferred at all. 2443 boolean usePreferred = true; 2444 try { 2445 usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android. 2446 internal.R.bool.config_dontPreferApn); 2447 } catch (Resources.NotFoundException e) { 2448 if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); 2449 usePreferred = true; 2450 } 2451 if (DBG) { 2452 log("buildWaitingApns: usePreferred=" + usePreferred 2453 + " canSetPreferApn=" + mCanSetPreferApn 2454 + " mPreferredApn=" + mPreferredApn 2455 + " operator=" + operator + " radioTech=" + radioTech 2456 + " IccRecords r=" + r); 2457 } 2458 2459 if (usePreferred && mCanSetPreferApn && mPreferredApn != null && 2460 mPreferredApn.canHandleType(requestedApnType)) { 2461 if (DBG) { 2462 log("buildWaitingApns: Preferred APN:" + operator + ":" 2463 + mPreferredApn.numeric + ":" + mPreferredApn); 2464 } 2465 if (mPreferredApn.numeric.equals(operator)) { 2466 if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) { 2467 apnList.add(mPreferredApn); 2468 if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); 2469 return apnList; 2470 } else { 2471 if (DBG) log("buildWaitingApns: no preferred APN"); 2472 setPreferredApn(-1); 2473 mPreferredApn = null; 2474 } 2475 } else { 2476 if (DBG) log("buildWaitingApns: no preferred APN"); 2477 setPreferredApn(-1); 2478 mPreferredApn = null; 2479 } 2480 } 2481 if (mAllApnSettings != null) { 2482 if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); 2483 for (ApnSetting apn : mAllApnSettings) { 2484 if (DBG) log("buildWaitingApns: apn=" + apn); 2485 if (apn.canHandleType(requestedApnType)) { 2486 if (apn.bearer == 0 || apn.bearer == radioTech) { 2487 if (DBG) log("buildWaitingApns: adding apn=" + apn.toString()); 2488 apnList.add(apn); 2489 } else { 2490 if (DBG) { 2491 log("buildWaitingApns: bearer:" + apn.bearer + " != " 2492 + "radioTech:" + radioTech); 2493 } 2494 } 2495 } else { 2496 if (DBG) { 2497 log("buildWaitingApns: couldn't handle requesedApnType=" 2498 + requestedApnType); 2499 } 2500 } 2501 } 2502 } else { 2503 loge("mAllApnSettings is empty!"); 2504 } 2505 if (DBG) log("buildWaitingApns: X apnList=" + apnList); 2506 return apnList; 2507 } 2508 2509 private String apnListToString (ArrayList<ApnSetting> apns) { 2510 StringBuilder result = new StringBuilder(); 2511 for (int i = 0, size = apns.size(); i < size; i++) { 2512 result.append('[') 2513 .append(apns.get(i).toString()) 2514 .append(']'); 2515 } 2516 return result.toString(); 2517 } 2518 2519 private void setPreferredApn(int pos) { 2520 if (!mCanSetPreferApn) { 2521 log("setPreferredApn: X !canSEtPreferApn"); 2522 return; 2523 } 2524 2525 String subId = Long.toString(mPhone.getSubId()); 2526 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 2527 log("setPreferredApn: delete"); 2528 ContentResolver resolver = mPhone.getContext().getContentResolver(); 2529 resolver.delete(uri, null, null); 2530 2531 if (pos >= 0) { 2532 log("setPreferredApn: insert"); 2533 ContentValues values = new ContentValues(); 2534 values.put(APN_ID, pos); 2535 resolver.insert(uri, values); 2536 } 2537 } 2538 2539 private ApnSetting getPreferredApn() { 2540 if (mAllApnSettings.isEmpty()) { 2541 log("getPreferredApn: X not found mAllApnSettings.isEmpty"); 2542 return null; 2543 } 2544 2545 String subId = Long.toString(mPhone.getSubId()); 2546 Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); 2547 Cursor cursor = mPhone.getContext().getContentResolver().query( 2548 uri, new String[] { "_id", "name", "apn" }, 2549 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); 2550 2551 if (cursor != null) { 2552 mCanSetPreferApn = true; 2553 } else { 2554 mCanSetPreferApn = false; 2555 } 2556 log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor 2557 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); 2558 2559 if (mCanSetPreferApn && cursor.getCount() > 0) { 2560 int pos; 2561 cursor.moveToFirst(); 2562 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); 2563 for(ApnSetting p : mAllApnSettings) { 2564 log("getPreferredApn: apnSetting=" + p); 2565 if (p.id == pos && p.canHandleType(mRequestedApnType)) { 2566 log("getPreferredApn: X found apnSetting" + p); 2567 cursor.close(); 2568 return p; 2569 } 2570 } 2571 } 2572 2573 if (cursor != null) { 2574 cursor.close(); 2575 } 2576 2577 log("getPreferredApn: X not found"); 2578 return null; 2579 } 2580 2581 @Override 2582 public void handleMessage (Message msg) { 2583 if (DBG) log("handleMessage msg=" + msg); 2584 2585 if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) { 2586 loge("handleMessage: Ignore GSM msgs since GSM phone is inactive"); 2587 return; 2588 } 2589 2590 switch (msg.what) { 2591 case DctConstants.EVENT_RECORDS_LOADED: 2592 onRecordsLoaded(); 2593 break; 2594 2595 case DctConstants.EVENT_DATA_CONNECTION_DETACHED: 2596 onDataConnectionDetached(); 2597 break; 2598 2599 case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: 2600 onDataConnectionAttached(); 2601 break; 2602 2603 case DctConstants.EVENT_DO_RECOVERY: 2604 doRecovery(); 2605 break; 2606 2607 case DctConstants.EVENT_APN_CHANGED: 2608 onApnChanged(); 2609 break; 2610 2611 case DctConstants.EVENT_PS_RESTRICT_ENABLED: 2612 /** 2613 * We don't need to explicitly to tear down the PDP context 2614 * when PS restricted is enabled. The base band will deactive 2615 * PDP context and notify us with PDP_CONTEXT_CHANGED. 2616 * But we should stop the network polling and prevent reset PDP. 2617 */ 2618 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); 2619 stopNetStatPoll(); 2620 stopDataStallAlarm(); 2621 mIsPsRestricted = true; 2622 break; 2623 2624 case DctConstants.EVENT_PS_RESTRICT_DISABLED: 2625 /** 2626 * When PS restrict is removed, we need setup PDP connection if 2627 * PDP connection is down. 2628 */ 2629 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); 2630 mIsPsRestricted = false; 2631 if (isConnected()) { 2632 startNetStatPoll(); 2633 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); 2634 } else { 2635 // TODO: Should all PDN states be checked to fail? 2636 if (mState == DctConstants.State.FAILED) { 2637 cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED); 2638 mReregisterOnReconnectFailure = false; 2639 } 2640 ApnContext apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT); 2641 if (apnContext != null) { 2642 apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); 2643 trySetupData(apnContext); 2644 } else { 2645 loge("**** Default ApnContext not found ****"); 2646 if (Build.IS_DEBUGGABLE) { 2647 throw new RuntimeException("Default ApnContext not found"); 2648 } 2649 } 2650 } 2651 break; 2652 2653 case DctConstants.EVENT_TRY_SETUP_DATA: 2654 if (msg.obj instanceof ApnContext) { 2655 onTrySetupData((ApnContext)msg.obj); 2656 } else if (msg.obj instanceof String) { 2657 onTrySetupData((String)msg.obj); 2658 } else { 2659 loge("EVENT_TRY_SETUP request w/o apnContext or String"); 2660 } 2661 break; 2662 2663 case DctConstants.EVENT_CLEAN_UP_CONNECTION: 2664 boolean tearDown = (msg.arg1 == 0) ? false : true; 2665 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown); 2666 if (msg.obj instanceof ApnContext) { 2667 cleanUpConnection(tearDown, (ApnContext)msg.obj); 2668 } else { 2669 loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context, call super"); 2670 super.handleMessage(msg); 2671 } 2672 break; 2673 case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: 2674 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false; 2675 onSetInternalDataEnabled(enabled, (Message) msg.obj); 2676 break; 2677 2678 case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: 2679 Message mCause = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null); 2680 if ((msg.obj != null) && (msg.obj instanceof String)) { 2681 mCause.obj = msg.obj; 2682 } 2683 super.handleMessage(mCause); 2684 break; 2685 2686 case DctConstants.EVENT_DATA_RAT_CHANGED: 2687 //May new Network allow setupData, so try it here 2688 setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED, 2689 RetryFailures.ONLY_ON_CHANGE); 2690 break; 2691 2692 case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: 2693 // Check message sender intended to clear the current spinner. 2694 if (mProvisioningSpinner == msg.obj) { 2695 mProvisioningSpinner.dismiss(); 2696 mProvisioningSpinner = null; 2697 } 2698 break; 2699 2700 default: 2701 // handle the message in the super class DataConnectionTracker 2702 super.handleMessage(msg); 2703 break; 2704 } 2705 } 2706 2707 protected int getApnProfileID(String apnType) { 2708 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 2709 return RILConstants.DATA_PROFILE_IMS; 2710 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) { 2711 return RILConstants.DATA_PROFILE_FOTA; 2712 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) { 2713 return RILConstants.DATA_PROFILE_CBS; 2714 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IA)) { 2715 return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now 2716 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_DUN)) { 2717 return RILConstants.DATA_PROFILE_TETHERED; 2718 } else { 2719 return RILConstants.DATA_PROFILE_DEFAULT; 2720 } 2721 } 2722 2723 private int getCellLocationId() { 2724 int cid = -1; 2725 CellLocation loc = mPhone.getCellLocation(); 2726 2727 if (loc != null) { 2728 if (loc instanceof GsmCellLocation) { 2729 cid = ((GsmCellLocation)loc).getCid(); 2730 } else if (loc instanceof CdmaCellLocation) { 2731 cid = ((CdmaCellLocation)loc).getBaseStationId(); 2732 } 2733 } 2734 return cid; 2735 } 2736 2737 private IccRecords getUiccRecords(int appFamily) { 2738 return mUiccController.getIccRecords(mPhone.getPhoneId(), appFamily); 2739 } 2740 2741 2742 @Override 2743 protected void onUpdateIcc() { 2744 if (mUiccController == null ) { 2745 return; 2746 } 2747 2748 IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP); 2749 2750 IccRecords r = mIccRecords.get(); 2751 if (r != newIccRecords) { 2752 if (r != null) { 2753 log("Removing stale icc objects."); 2754 r.unregisterForRecordsLoaded(this); 2755 mIccRecords.set(null); 2756 } 2757 if (newIccRecords != null) { 2758 log("New records found"); 2759 mIccRecords.set(newIccRecords); 2760 newIccRecords.registerForRecordsLoaded( 2761 this, DctConstants.EVENT_RECORDS_LOADED, null); 2762 } 2763 } 2764 } 2765 2766 public void update() { 2767 log("update sub = " + mPhone.getSubId()); 2768 log("update(): Active DDS, register for all events now!"); 2769 registerForAllEvents(); 2770 onUpdateIcc(); 2771 2772 mUserDataEnabled = getDataEnabled(); 2773 2774 if (mPhone instanceof CDMALTEPhone) { 2775 ((CDMALTEPhone)mPhone).updateCurrentCarrierInProvider(); 2776 supplyMessenger(); 2777 } else if (mPhone instanceof GSMPhone) { 2778 ((GSMPhone)mPhone).updateCurrentCarrierInProvider(); 2779 supplyMessenger(); 2780 } else { 2781 log("Phone object is not MultiSim. This should not hit!!!!"); 2782 } 2783 } 2784 2785 @Override 2786 public void cleanUpAllConnections(String cause) { 2787 cleanUpAllConnections(cause, null); 2788 } 2789 2790 public void updateRecords() { 2791 onUpdateIcc(); 2792 } 2793 2794 public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) { 2795 log("cleanUpAllConnections"); 2796 if (disconnectAllCompleteMsg != null) { 2797 mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg); 2798 } 2799 2800 Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); 2801 msg.obj = cause; 2802 sendMessage(msg); 2803 } 2804 2805 protected void notifyDataDisconnectComplete() { 2806 log("notifyDataDisconnectComplete"); 2807 for (Message m: mDisconnectAllCompleteMsgList) { 2808 m.sendToTarget(); 2809 } 2810 mDisconnectAllCompleteMsgList.clear(); 2811 } 2812 2813 2814 protected void notifyAllDataDisconnected() { 2815 sEnableFailFastRefCounter = 0; 2816 mFailFast = false; 2817 mAllDataDisconnectedRegistrants.notifyRegistrants(); 2818 } 2819 2820 public void registerForAllDataDisconnected(Handler h, int what, Object obj) { 2821 mAllDataDisconnectedRegistrants.addUnique(h, what, obj); 2822 2823 if (isDisconnected()) { 2824 log("notify All Data Disconnected"); 2825 notifyAllDataDisconnected(); 2826 } 2827 } 2828 2829 public void unregisterForAllDataDisconnected(Handler h) { 2830 mAllDataDisconnectedRegistrants.remove(h); 2831 } 2832 2833 2834 @Override 2835 protected void onSetInternalDataEnabled(boolean enable) { 2836 if (DBG) log("onSetInternalDataEnabled: enabled=" + enable); 2837 onSetInternalDataEnabled(enable, null); 2838 } 2839 2840 protected void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) { 2841 if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled); 2842 boolean sendOnComplete = true; 2843 2844 synchronized (mDataEnabledLock) { 2845 mInternalDataEnabled = enabled; 2846 if (enabled) { 2847 log("onSetInternalDataEnabled: changed to enabled, try to setup data call"); 2848 onTrySetupData(Phone.REASON_DATA_ENABLED); 2849 } else { 2850 sendOnComplete = false; 2851 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections"); 2852 cleanUpAllConnections(null, onCompleteMsg); 2853 } 2854 } 2855 2856 if (sendOnComplete) { 2857 if (onCompleteMsg != null) { 2858 onCompleteMsg.sendToTarget(); 2859 } 2860 } 2861 } 2862 2863 public boolean setInternalDataEnabledFlag(boolean enable) { 2864 if (DBG) log("setInternalDataEnabledFlag(" + enable + ")"); 2865 2866 if (mInternalDataEnabled != enable) { 2867 mInternalDataEnabled = enable; 2868 } 2869 return true; 2870 } 2871 2872 @Override 2873 public boolean setInternalDataEnabled(boolean enable) { 2874 return setInternalDataEnabled(enable, null); 2875 } 2876 2877 public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) { 2878 if (DBG) log("setInternalDataEnabled(" + enable + ")"); 2879 2880 Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg); 2881 msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED); 2882 sendMessage(msg); 2883 return true; 2884 } 2885 2886 public void setDataAllowed(boolean enable, Message response) { 2887 if (DBG) log("setDataAllowed: enable=" + enable); 2888 mIsCleanupRequired = !enable; 2889 mPhone.mCi.setDataAllowed(enable, response); 2890 mInternalDataEnabled = enable; 2891 } 2892 2893 @Override 2894 protected void log(String s) { 2895 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 2896 } 2897 2898 @Override 2899 protected void loge(String s) { 2900 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 2901 } 2902 2903 @Override 2904 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2905 pw.println("DcTracker extends:"); 2906 super.dump(fd, pw, args); 2907 pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); 2908 pw.println(" canSetPreferApn=" + mCanSetPreferApn); 2909 pw.println(" mApnObserver=" + mApnObserver); 2910 pw.println(" getOverallState=" + getOverallState()); 2911 pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap); 2912 pw.println(" mAttached=" + mAttached.get()); 2913 } 2914 2915 @Override 2916 public String[] getPcscfAddress(String apnType) { 2917 log("getPcscfAddress()"); 2918 ApnContext apnContext = null; 2919 2920 if(apnType == null){ 2921 log("apnType is null, return null"); 2922 return null; 2923 } 2924 2925 if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_EMERGENCY)) { 2926 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_EMERGENCY); 2927 } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) { 2928 apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_IMS); 2929 } else { 2930 log("apnType is invalid, return null"); 2931 return null; 2932 } 2933 2934 if (apnContext == null) { 2935 log("apnContext is null, return null"); 2936 return null; 2937 } 2938 2939 DcAsyncChannel dcac = apnContext.getDcAc(); 2940 String[] result = null; 2941 2942 if (dcac != null) { 2943 result = dcac.getPcscfAddr(); 2944 2945 for (int i = 0; i < result.length; i++) { 2946 log("Pcscf[" + i + "]: " + result[i]); 2947 } 2948 return result; 2949 } 2950 return null; 2951 } 2952 2953 @Override 2954 public void setImsRegistrationState(boolean registered) { 2955 log("setImsRegistrationState - mImsRegistrationState(before): "+ mImsRegistrationState 2956 + ", registered(current) : " + registered); 2957 2958 if (mPhone == null) return; 2959 2960 ServiceStateTracker sst = mPhone.getServiceStateTracker(); 2961 if (sst == null) return; 2962 2963 sst.setImsRegistrationState(registered); 2964 } 2965 2966 /** 2967 * Read APN configuration from Telephony.db for Emergency APN 2968 * All opertors recognize the connection request for EPDN based on APN type 2969 * PLMN name,APN name are not mandatory parameters 2970 */ 2971 private void initEmergencyApnSetting() { 2972 // Operator Numeric is not available when sim records are not loaded. 2973 // Query Telephony.db with APN type as EPDN request does not 2974 // require APN name, plmn and all operators support same APN config. 2975 // DB will contain only one entry for Emergency APN 2976 String selection = "type=\"emergency\""; 2977 Cursor cursor = mPhone.getContext().getContentResolver().query( 2978 Telephony.Carriers.CONTENT_URI, null, selection, null, null); 2979 2980 if (cursor != null) { 2981 if (cursor.getCount() > 0) { 2982 if (cursor.moveToFirst()) { 2983 mEmergencyApn = makeApnSetting(cursor); 2984 } 2985 } 2986 cursor.close(); 2987 } 2988 } 2989 2990 /** 2991 * Add the Emergency APN settings to APN settings list 2992 */ 2993 private void addEmergencyApnSetting() { 2994 if(mEmergencyApn != null) { 2995 if(mAllApnSettings == null) { 2996 mAllApnSettings = new ArrayList<ApnSetting>(); 2997 } else { 2998 boolean hasEmergencyApn = false; 2999 for (ApnSetting apn : mAllApnSettings) { 3000 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) { 3001 hasEmergencyApn = true; 3002 break; 3003 } 3004 } 3005 3006 if(hasEmergencyApn == false) { 3007 mAllApnSettings.add(mEmergencyApn); 3008 } else { 3009 log("addEmergencyApnSetting - E-APN setting is already present"); 3010 } 3011 } 3012 } 3013 } 3014 3015 private void cleanUpConnectionsOnUpdatedApns(boolean tearDown) { 3016 if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown); 3017 if (mAllApnSettings.isEmpty()) { 3018 cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED); 3019 } else { 3020 for (ApnContext apnContext : mApnContexts.values()) { 3021 if (VDBG) log("cleanUpConnectionsOnUpdatedApns for "+ apnContext); 3022 3023 boolean cleanUpApn = true; 3024 ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns(); 3025 3026 if ((currentWaitingApns != null) && (!apnContext.isDisconnected())) { 3027 int radioTech = mPhone.getServiceState().getRilDataRadioTechnology(); 3028 ArrayList<ApnSetting> waitingApns = buildWaitingApns( 3029 apnContext.getApnType(), radioTech); 3030 if (VDBG) log("new waitingApns:" + waitingApns); 3031 if (waitingApns.size() == currentWaitingApns.size()) { 3032 cleanUpApn = false; 3033 for (int i = 0; i < waitingApns.size(); i++) { 3034 if (!currentWaitingApns.get(i).equals(waitingApns.get(i))) { 3035 if (VDBG) log("new waiting apn is different at " + i); 3036 cleanUpApn = true; 3037 apnContext.setWaitingApns(waitingApns); 3038 break; 3039 } 3040 } 3041 } 3042 } 3043 3044 if (cleanUpApn) { 3045 apnContext.setReason(Phone.REASON_APN_CHANGED); 3046 cleanUpConnection(true, apnContext); 3047 } 3048 } 3049 } 3050 3051 if (!isConnected()) { 3052 stopNetStatPoll(); 3053 stopDataStallAlarm(); 3054 } 3055 3056 mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT; 3057 3058 if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount); 3059 if (tearDown && mDisconnectPendingCount == 0) { 3060 notifyDataDisconnectComplete(); 3061 notifyAllDataDisconnected(); 3062 } 3063 } 3064} 3065