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