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