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