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