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