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.content.ActivityNotFoundException;
     22 import android.content.ContentResolver;
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.res.Resources;
     28 import android.database.ContentObserver;
     29 import android.database.Cursor;
     30 import android.net.ConnectivityManager;
     31 import android.net.LinkCapabilities;
     32 import android.net.LinkProperties;
     33 import android.net.NetworkConfig;
     34 import android.net.NetworkUtils;
     35 import android.net.ProxyProperties;
     36 import android.net.Uri;
     37 import android.os.AsyncResult;
     38 import android.os.Message;
     39 import android.os.Messenger;
     40 import android.os.SystemClock;
     41 import android.os.SystemProperties;
     42 import android.os.UserHandle;
     43 import android.provider.Settings;
     44 import android.provider.Telephony;
     45 import android.telephony.CellLocation;
     46 import android.telephony.ServiceState;
     47 import android.telephony.TelephonyManager;
     48 import android.telephony.cdma.CdmaCellLocation;
     49 import android.telephony.gsm.GsmCellLocation;
     50 import android.text.TextUtils;
     51 import android.util.EventLog;
     52 import android.telephony.Rlog;
     53 
     54 import com.android.internal.telephony.Phone;
     55 import com.android.internal.telephony.PhoneBase;
     56 import com.android.internal.telephony.DctConstants;
     57 import com.android.internal.telephony.EventLogTags;
     58 import com.android.internal.telephony.TelephonyIntents;
     59 import com.android.internal.telephony.gsm.GSMPhone;
     60 import com.android.internal.telephony.PhoneConstants;
     61 import com.android.internal.telephony.RILConstants;
     62 import com.android.internal.telephony.uicc.IccRecords;
     63 import com.android.internal.telephony.uicc.UiccController;
     64 import com.android.internal.util.AsyncChannel;
     65 
     66 import java.io.FileDescriptor;
     67 import java.io.PrintWriter;
     68 import java.util.ArrayList;
     69 import java.util.HashMap;
     70 
     71 /**
     72  * {@hide}
     73  */
     74 public final class DcTracker extends DcTrackerBase {
     75     protected final String LOG_TAG = "DCT";
     76 
     77     /**
     78      * Handles changes to the APN db.
     79      */
     80     private class ApnChangeObserver extends ContentObserver {
     81         public ApnChangeObserver () {
     82             super(mDataConnectionTracker);
     83         }
     84 
     85         @Override
     86         public void onChange(boolean selfChange) {
     87             sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED));
     88         }
     89     }
     90 
     91     //***** Instance Variables
     92 
     93     private boolean mReregisterOnReconnectFailure = false;
     94 
     95 
     96     //***** Constants
     97 
     98     // Used by puppetmaster/*/radio_stress.py
     99     private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
    100 
    101     private static final int POLL_PDP_MILLIS = 5 * 1000;
    102 
    103     static final Uri PREFERAPN_NO_UPDATE_URI =
    104                         Uri.parse("content://telephony/carriers/preferapn_no_update");
    105     static final String APN_ID = "apn_id";
    106 
    107     private boolean mCanSetPreferApn = false;
    108 
    109     /** Watches for changes to the APN db. */
    110     private ApnChangeObserver mApnObserver;
    111 
    112     //***** Constructor
    113 
    114     public DcTracker(PhoneBase p) {
    115         super(p);
    116         if (DBG) log("GsmDCT.constructor");
    117         p.mCi.registerForAvailable (this, DctConstants.EVENT_RADIO_AVAILABLE, null);
    118         p.mCi.registerForOffOrNotAvailable(this, DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE,
    119                 null);
    120         p.mCi.registerForDataNetworkStateChanged (this, DctConstants.EVENT_DATA_STATE_CHANGED,
    121                 null);
    122         p.getCallTracker().registerForVoiceCallEnded (this, DctConstants.EVENT_VOICE_CALL_ENDED,
    123                 null);
    124         p.getCallTracker().registerForVoiceCallStarted (this, DctConstants.EVENT_VOICE_CALL_STARTED,
    125                 null);
    126         p.getServiceStateTracker().registerForDataConnectionAttached(this,
    127                 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
    128         p.getServiceStateTracker().registerForDataConnectionDetached(this,
    129                 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
    130         p.getServiceStateTracker().registerForRoamingOn(this, DctConstants.EVENT_ROAMING_ON, null);
    131         p.getServiceStateTracker().registerForRoamingOff(this, DctConstants.EVENT_ROAMING_OFF,
    132                 null);
    133         p.getServiceStateTracker().registerForPsRestrictedEnabled(this,
    134                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
    135         p.getServiceStateTracker().registerForPsRestrictedDisabled(this,
    136                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
    137 
    138         mDataConnectionTracker = this;
    139 
    140         mApnObserver = new ApnChangeObserver();
    141         p.getContext().getContentResolver().registerContentObserver(
    142                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
    143 
    144         initApnContextsAndDataConnection();
    145 
    146         for (ApnContext apnContext : mApnContexts.values()) {
    147             // Register the reconnect and restart actions.
    148             IntentFilter filter = new IntentFilter();
    149             filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
    150             filter.addAction(INTENT_RESTART_TRYSETUP_ALARM + '.' + apnContext.getApnType());
    151             mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
    152         }
    153 
    154         ConnectivityManager cm = (ConnectivityManager)p.getContext().getSystemService(
    155                 Context.CONNECTIVITY_SERVICE);
    156         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE, new Messenger(this));
    157         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_MMS, new Messenger(this));
    158         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_SUPL, new Messenger(this));
    159         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_DUN, new Messenger(this));
    160         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_HIPRI, new Messenger(this));
    161         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_FOTA, new Messenger(this));
    162         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_IMS, new Messenger(this));
    163         cm.supplyMessenger(ConnectivityManager.TYPE_MOBILE_CBS, new Messenger(this));
    164     }
    165 
    166     @Override
    167     public void dispose() {
    168         if (DBG) log("GsmDCT.dispose");
    169         cleanUpAllConnections(true, null);
    170 
    171         super.dispose();
    172 
    173         //Unregister for all events
    174         mPhone.mCi.unregisterForAvailable(this);
    175         mPhone.mCi.unregisterForOffOrNotAvailable(this);
    176         IccRecords r = mIccRecords.get();
    177         if (r != null) { r.unregisterForRecordsLoaded(this);}
    178         mPhone.mCi.unregisterForDataNetworkStateChanged(this);
    179         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
    180         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
    181         mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
    182         mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
    183         mPhone.getServiceStateTracker().unregisterForRoamingOn(this);
    184         mPhone.getServiceStateTracker().unregisterForRoamingOff(this);
    185         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
    186         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
    187 
    188         mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver);
    189         mApnContexts.clear();
    190 
    191         destroyDataConnections();
    192     }
    193 
    194     @Override
    195     public boolean isApnTypeActive(String type) {
    196         ApnContext apnContext = mApnContexts.get(type);
    197         if (apnContext == null) return false;
    198 
    199         return (apnContext.getDcAc() != null);
    200     }
    201 
    202     @Override
    203     public boolean isDataPossible(String apnType) {
    204         ApnContext apnContext = mApnContexts.get(apnType);
    205         if (apnContext == null) {
    206             return false;
    207         }
    208         boolean apnContextIsEnabled = apnContext.isEnabled();
    209         DctConstants.State apnContextState = apnContext.getState();
    210         boolean apnTypePossible = !(apnContextIsEnabled &&
    211                 (apnContextState == DctConstants.State.FAILED));
    212         boolean dataAllowed = isDataAllowed();
    213         boolean possible = dataAllowed && apnTypePossible;
    214 
    215         if (VDBG) {
    216             log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
    217                     "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
    218                     apnType, possible, dataAllowed, apnTypePossible,
    219                     apnContextIsEnabled, apnContextState));
    220         }
    221         return possible;
    222     }
    223 
    224     @Override
    225     protected void finalize() {
    226         if(DBG) log("finalize");
    227     }
    228 
    229     private ApnContext addApnContext(String type) {
    230         ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
    231         apnContext.setDependencyMet(false);
    232         mApnContexts.put(type, apnContext);
    233         return apnContext;
    234     }
    235 
    236     protected void initApnContextsAndDataConnection() {
    237         boolean defaultEnabled = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP, true);
    238         // Load device network attributes from resources
    239         String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
    240                 com.android.internal.R.array.networkAttributes);
    241         for (String networkConfigString : networkConfigStrings) {
    242             NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
    243             ApnContext apnContext = null;
    244 
    245             switch (networkConfig.type) {
    246             case ConnectivityManager.TYPE_MOBILE:
    247                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT);
    248                 apnContext.setEnabled(defaultEnabled);
    249                 break;
    250             case ConnectivityManager.TYPE_MOBILE_MMS:
    251                 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS);
    252                 break;
    253             case ConnectivityManager.TYPE_MOBILE_SUPL:
    254                 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL);
    255                 break;
    256             case ConnectivityManager.TYPE_MOBILE_DUN:
    257                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN);
    258                 break;
    259             case ConnectivityManager.TYPE_MOBILE_HIPRI:
    260                 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI);
    261                 ApnContext defaultContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT);
    262                 if (defaultContext != null) {
    263                     applyNewState(apnContext, apnContext.isEnabled(),
    264                             defaultContext.getDependencyMet());
    265                 } else {
    266                     // the default will set the hipri dep-met when it is created
    267                 }
    268                 continue;
    269             case ConnectivityManager.TYPE_MOBILE_FOTA:
    270                 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA);
    271                 break;
    272             case ConnectivityManager.TYPE_MOBILE_IMS:
    273                 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS);
    274                 break;
    275             case ConnectivityManager.TYPE_MOBILE_CBS:
    276                 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS);
    277                 break;
    278             default:
    279                 // skip unknown types
    280                 continue;
    281             }
    282             if (apnContext != null) {
    283                 // set the prop, but also apply the newly set enabled and dependency values
    284                 onSetDependencyMet(apnContext.getApnType(), networkConfig.dependencyMet);
    285             }
    286         }
    287     }
    288 
    289     @Override
    290     public LinkProperties getLinkProperties(String apnType) {
    291         ApnContext apnContext = mApnContexts.get(apnType);
    292         if (apnContext != null) {
    293             DcAsyncChannel dcac = apnContext.getDcAc();
    294             if (dcac != null) {
    295                 if (DBG) log("return link properites for " + apnType);
    296                 return dcac.getLinkPropertiesSync();
    297             }
    298         }
    299         if (DBG) log("return new LinkProperties");
    300         return new LinkProperties();
    301     }
    302 
    303     @Override
    304     public LinkCapabilities getLinkCapabilities(String apnType) {
    305         ApnContext apnContext = mApnContexts.get(apnType);
    306         if (apnContext!=null) {
    307             DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
    308             if (dataConnectionAc != null) {
    309                 if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
    310                 return dataConnectionAc.getLinkCapabilitiesSync();
    311             }
    312         }
    313         if (DBG) log("return new LinkCapabilities");
    314         return new LinkCapabilities();
    315     }
    316 
    317     @Override
    318     // Return all active apn types
    319     public String[] getActiveApnTypes() {
    320         if (DBG) log("get all active apn types");
    321         ArrayList<String> result = new ArrayList<String>();
    322 
    323         for (ApnContext apnContext : mApnContexts.values()) {
    324             if (apnContext.isReady()) {
    325                 result.add(apnContext.getApnType());
    326             }
    327         }
    328 
    329         return result.toArray(new String[0]);
    330     }
    331 
    332     @Override
    333     // Return active apn of specific apn type
    334     public String getActiveApnString(String apnType) {
    335         if (VDBG) log( "get active apn string for type:" + apnType);
    336         ApnContext apnContext = mApnContexts.get(apnType);
    337         if (apnContext != null) {
    338             ApnSetting apnSetting = apnContext.getApnSetting();
    339             if (apnSetting != null) {
    340                 return apnSetting.apn;
    341             }
    342         }
    343         return null;
    344     }
    345 
    346     @Override
    347     public boolean isApnTypeEnabled(String apnType) {
    348         ApnContext apnContext = mApnContexts.get(apnType);
    349         if (apnContext == null) {
    350             return false;
    351         }
    352         return apnContext.isEnabled();
    353     }
    354 
    355     @Override
    356     protected void setState(DctConstants.State s) {
    357         if (DBG) log("setState should not be used in GSM" + s);
    358     }
    359 
    360     // Return state of specific apn type
    361     @Override
    362     public DctConstants.State getState(String apnType) {
    363         ApnContext apnContext = mApnContexts.get(apnType);
    364         if (apnContext != null) {
    365             return apnContext.getState();
    366         }
    367         return DctConstants.State.FAILED;
    368     }
    369 
    370     // Return if apn type is a provisioning apn.
    371     @Override
    372     protected boolean isProvisioningApn(String apnType) {
    373         ApnContext apnContext = mApnContexts.get(apnType);
    374         if (apnContext != null) {
    375             return apnContext.isProvisioningApn();
    376         }
    377         return false;
    378     }
    379 
    380     // Return state of overall
    381     @Override
    382     public DctConstants.State getOverallState() {
    383         boolean isConnecting = false;
    384         boolean isFailed = true; // All enabled Apns should be FAILED.
    385         boolean isAnyEnabled = false;
    386 
    387         for (ApnContext apnContext : mApnContexts.values()) {
    388             if (apnContext.isEnabled()) {
    389                 isAnyEnabled = true;
    390                 switch (apnContext.getState()) {
    391                 case CONNECTED:
    392                 case DISCONNECTING:
    393                     if (DBG) log("overall state is CONNECTED");
    394                     return DctConstants.State.CONNECTED;
    395                 case RETRYING:
    396                 case CONNECTING:
    397                     isConnecting = true;
    398                     isFailed = false;
    399                     break;
    400                 case IDLE:
    401                 case SCANNING:
    402                     isFailed = false;
    403                     break;
    404                 default:
    405                     isAnyEnabled = true;
    406                     break;
    407                 }
    408             }
    409         }
    410 
    411         if (!isAnyEnabled) { // Nothing enabled. return IDLE.
    412             if (DBG) log( "overall state is IDLE");
    413             return DctConstants.State.IDLE;
    414         }
    415 
    416         if (isConnecting) {
    417             if (DBG) log( "overall state is CONNECTING");
    418             return DctConstants.State.CONNECTING;
    419         } else if (!isFailed) {
    420             if (DBG) log( "overall state is IDLE");
    421             return DctConstants.State.IDLE;
    422         } else {
    423             if (DBG) log( "overall state is FAILED");
    424             return DctConstants.State.FAILED;
    425         }
    426     }
    427 
    428     /**
    429      * Ensure that we are connected to an APN of the specified type.
    430      *
    431      * @param apnType the APN type
    432      * @return Success is indicated by {@code PhoneConstants.APN_ALREADY_ACTIVE} or
    433      *         {@code PhoneConstants.APN_REQUEST_STARTED}. In the latter case, a
    434      *         broadcast will be sent by the ConnectivityManager when a
    435      *         connection to the APN has been established.
    436      */
    437     @Override
    438     public synchronized int enableApnType(String apnType) {
    439         ApnContext apnContext = mApnContexts.get(apnType);
    440         if (apnContext == null || !isApnTypeAvailable(apnType)) {
    441             if (DBG) log("enableApnType: " + apnType + " is type not available");
    442             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
    443         }
    444 
    445         // If already active, return
    446         if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")");
    447 
    448         if (apnContext.getState() == DctConstants.State.CONNECTED) {
    449             if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE");
    450             return PhoneConstants.APN_ALREADY_ACTIVE;
    451         }
    452         setEnabled(apnTypeToId(apnType), true);
    453         if (DBG) {
    454             log("enableApnType: new apn request for type " + apnType +
    455                     " return APN_REQUEST_STARTED");
    456         }
    457         return PhoneConstants.APN_REQUEST_STARTED;
    458     }
    459 
    460     @Override
    461     public synchronized int disableApnType(String type) {
    462         if (DBG) log("disableApnType:" + type);
    463         ApnContext apnContext = mApnContexts.get(type);
    464 
    465         if (apnContext != null) {
    466             setEnabled(apnTypeToId(type), false);
    467             if (apnContext.getState() != DctConstants.State.IDLE && apnContext.getState()
    468                     != DctConstants.State.FAILED) {
    469                 if (DBG) log("diableApnType: return APN_REQUEST_STARTED");
    470                 return PhoneConstants.APN_REQUEST_STARTED;
    471             } else {
    472                 if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE");
    473                 return PhoneConstants.APN_ALREADY_INACTIVE;
    474             }
    475 
    476         } else {
    477             if (DBG) {
    478                 log("disableApnType: no apn context was found, return APN_REQUEST_FAILED");
    479             }
    480             return PhoneConstants.APN_REQUEST_FAILED;
    481         }
    482     }
    483 
    484     @Override
    485     protected boolean isApnTypeAvailable(String type) {
    486         if (type.equals(PhoneConstants.APN_TYPE_DUN) && fetchDunApn() != null) {
    487             return true;
    488         }
    489 
    490         if (mAllApnSettings != null) {
    491             for (ApnSetting apn : mAllApnSettings) {
    492                 if (apn.canHandleType(type)) {
    493                     return true;
    494                 }
    495             }
    496         }
    497         return false;
    498     }
    499 
    500     /**
    501      * Report on whether data connectivity is enabled for any APN.
    502      * @return {@code false} if data connectivity has been explicitly disabled,
    503      * {@code true} otherwise.
    504      */
    505     @Override
    506     public boolean getAnyDataEnabled() {
    507         synchronized (mDataEnabledLock) {
    508             if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false;
    509             for (ApnContext apnContext : mApnContexts.values()) {
    510                 // Make sure we don't have a context that is going down
    511                 // and is explicitly disabled.
    512                 if (isDataAllowed(apnContext)) {
    513                     return true;
    514                 }
    515             }
    516             return false;
    517         }
    518     }
    519 
    520     private boolean isDataAllowed(ApnContext apnContext) {
    521         return apnContext.isReady() && isDataAllowed();
    522     }
    523 
    524     //****** Called from ServiceStateTracker
    525     /**
    526      * Invoked when ServiceStateTracker observes a transition from GPRS
    527      * attach to detach.
    528      */
    529     protected void onDataConnectionDetached() {
    530         /*
    531          * We presently believe it is unnecessary to tear down the PDP context
    532          * when GPRS detaches, but we should stop the network polling.
    533          */
    534         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
    535         stopNetStatPoll();
    536         stopDataStallAlarm();
    537         notifyDataConnection(Phone.REASON_DATA_DETACHED);
    538     }
    539 
    540     private void onDataConnectionAttached() {
    541         if (DBG) log("onDataConnectionAttached");
    542         if (getOverallState() == DctConstants.State.CONNECTED) {
    543             if (DBG) log("onDataConnectionAttached: start polling notify attached");
    544             startNetStatPoll();
    545             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
    546             notifyDataConnection(Phone.REASON_DATA_ATTACHED);
    547         } else {
    548             // update APN availability so that APN can be enabled.
    549             notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
    550         }
    551         mAutoAttachOnCreation = true;
    552         setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
    553     }
    554 
    555     @Override
    556     protected boolean isDataAllowed() {
    557         final boolean internalDataEnabled;
    558         synchronized (mDataEnabledLock) {
    559             internalDataEnabled = mInternalDataEnabled;
    560         }
    561 
    562         int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
    563         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
    564         IccRecords r = mIccRecords.get();
    565         boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false;
    566 
    567         boolean allowed =
    568                     (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
    569                     recordsLoaded &&
    570                     (mPhone.getState() == PhoneConstants.State.IDLE ||
    571                      mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
    572                     internalDataEnabled &&
    573                     (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
    574                     !mIsPsRestricted &&
    575                     desiredPowerState;
    576         if (!allowed && DBG) {
    577             String reason = "";
    578             if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
    579                 reason += " - gprs= " + gprsState;
    580             }
    581             if (!recordsLoaded) reason += " - SIM not loaded";
    582             if (mPhone.getState() != PhoneConstants.State.IDLE &&
    583                     !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
    584                 reason += " - PhoneState= " + mPhone.getState();
    585                 reason += " - Concurrent voice and data not allowed";
    586             }
    587             if (!internalDataEnabled) reason += " - mInternalDataEnabled= false";
    588             if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
    589                 reason += " - Roaming and data roaming not enabled";
    590             }
    591             if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
    592             if (!desiredPowerState) reason += " - desiredPowerState= false";
    593             if (DBG) log("isDataAllowed: not allowed due to" + reason);
    594         }
    595         return allowed;
    596     }
    597 
    598     private void setupDataOnConnectableApns(String reason) {
    599         for (ApnContext apnContext : mApnContexts.values()) {
    600             if (apnContext.getState() == DctConstants.State.FAILED) {
    601                 apnContext.setState(DctConstants.State.IDLE);
    602             }
    603             if (apnContext.isConnectable()) {
    604                 log("setupDataOnConnectableApns: isConnectable() call trySetupData");
    605                 apnContext.setReason(reason);
    606                 trySetupData(apnContext);
    607             }
    608         }
    609     }
    610 
    611     private boolean trySetupData(String reason, String type) {
    612         if (DBG) {
    613             log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
    614                     + " isPsRestricted=" + mIsPsRestricted);
    615         }
    616 
    617         if (type == null) {
    618             type = PhoneConstants.APN_TYPE_DEFAULT;
    619         }
    620 
    621         ApnContext apnContext = mApnContexts.get(type);
    622 
    623         if (apnContext == null ){
    624             if (DBG) log("trySetupData new apn context for type:" + type);
    625             apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
    626             mApnContexts.put(type, apnContext);
    627         }
    628         apnContext.setReason(reason);
    629 
    630         return trySetupData(apnContext);
    631     }
    632 
    633     private boolean trySetupData(ApnContext apnContext) {
    634         if (DBG) {
    635             log("trySetupData for type:" + apnContext.getApnType() +
    636                     " due to " + apnContext.getReason() + " apnContext=" + apnContext);
    637             log("trySetupData with mIsPsRestricted=" + mIsPsRestricted);
    638         }
    639 
    640         if (mPhone.getSimulatedRadioControl() != null) {
    641             // Assume data is connected on the simulator
    642             // FIXME  this can be improved
    643             apnContext.setState(DctConstants.State.CONNECTED);
    644             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
    645 
    646             log("trySetupData: X We're on the simulator; assuming connected retValue=true");
    647             return true;
    648         }
    649 
    650         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
    651 
    652         if (apnContext.isConnectable() &&
    653                 isDataAllowed(apnContext) && getAnyDataEnabled() && !isEmergency()) {
    654             if (apnContext.getState() == DctConstants.State.FAILED) {
    655                 if (DBG) log("trySetupData: make a FAILED ApnContext IDLE so its reusable");
    656                 apnContext.setState(DctConstants.State.IDLE);
    657             }
    658             if (apnContext.getState() == DctConstants.State.IDLE) {
    659                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
    660                 if (waitingApns.isEmpty()) {
    661                     notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
    662                     notifyOffApnsOfAvailability(apnContext.getReason());
    663                     if (DBG) log("trySetupData: X No APN found retValue=false");
    664                     return false;
    665                 } else {
    666                     apnContext.setWaitingApns(waitingApns);
    667                     if (DBG) {
    668                         log ("trySetupData: Create from mAllApnSettings : "
    669                                     + apnListToString(mAllApnSettings));
    670                     }
    671                 }
    672             }
    673 
    674             if (DBG) {
    675                 log("trySetupData: call setupData, waitingApns : "
    676                         + apnListToString(apnContext.getWaitingApns()));
    677             }
    678             boolean retValue = setupData(apnContext);
    679             notifyOffApnsOfAvailability(apnContext.getReason());
    680 
    681             if (DBG) log("trySetupData: X retValue=" + retValue);
    682             return retValue;
    683         } else {
    684             if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
    685                     && apnContext.isConnectable()) {
    686                 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
    687             }
    688             notifyOffApnsOfAvailability(apnContext.getReason());
    689             if (DBG) log ("trySetupData: X apnContext not 'ready' retValue=false");
    690             return false;
    691         }
    692     }
    693 
    694     @Override
    695     // Disabled apn's still need avail/unavail notificiations - send them out
    696     protected void notifyOffApnsOfAvailability(String reason) {
    697         for (ApnContext apnContext : mApnContexts.values()) {
    698             if (!apnContext.isReady()) {
    699                 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
    700                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
    701                                             apnContext.getApnType(),
    702                                             PhoneConstants.DataState.DISCONNECTED);
    703             } else {
    704                 if (VDBG) {
    705                     log("notifyOffApnsOfAvailability skipped apn due to isReady==true: " +
    706                             apnContext.toString());
    707                 }
    708             }
    709         }
    710     }
    711 
    712     /**
    713      * If tearDown is true, this only tears down a CONNECTED session. Presently,
    714      * there is no mechanism for abandoning an CONNECTING session,
    715      * but would likely involve cancelling pending async requests or
    716      * setting a flag or new state to ignore them when they came in
    717      * @param tearDown true if the underlying DataConnection should be
    718      * disconnected.
    719      * @param reason reason for the clean up.
    720      */
    721     protected void cleanUpAllConnections(boolean tearDown, String reason) {
    722         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
    723 
    724         for (ApnContext apnContext : mApnContexts.values()) {
    725             apnContext.setReason(reason);
    726             cleanUpConnection(tearDown, apnContext);
    727         }
    728 
    729         stopNetStatPoll();
    730         stopDataStallAlarm();
    731 
    732         // TODO: Do we need mRequestedApnType?
    733         mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
    734     }
    735 
    736     /**
    737      * Cleanup all connections.
    738      *
    739      * TODO: Cleanup only a specified connection passed as a parameter.
    740      *       Also, make sure when you clean up a conn, if it is last apply
    741      *       logic as though it is cleanupAllConnections
    742      *
    743      * @param cause for the clean up.
    744      */
    745 
    746     @Override
    747     protected void onCleanUpAllConnections(String cause) {
    748         cleanUpAllConnections(true, cause);
    749     }
    750 
    751     private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
    752 
    753         if (apnContext == null) {
    754             if (DBG) log("cleanUpConnection: apn context is null");
    755             return;
    756         }
    757 
    758         DcAsyncChannel dcac = apnContext.getDcAc();
    759         if (DBG) {
    760             log("cleanUpConnection: E tearDown=" + tearDown + " reason=" + apnContext.getReason() +
    761                     " apnContext=" + apnContext);
    762         }
    763         if (tearDown) {
    764             if (apnContext.isDisconnected()) {
    765                 // The request is tearDown and but ApnContext is not connected.
    766                 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
    767                 apnContext.setState(DctConstants.State.IDLE);
    768                 if (!apnContext.isReady()) {
    769                     if (dcac != null) {
    770                         dcac.tearDown(apnContext, "", null);
    771                     }
    772                     apnContext.setDataConnectionAc(null);
    773                 }
    774             } else {
    775                 // Connection is still there. Try to clean up.
    776                 if (dcac != null) {
    777                     if (apnContext.getState() != DctConstants.State.DISCONNECTING) {
    778                         boolean disconnectAll = false;
    779                         if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) {
    780                             ApnSetting dunSetting = fetchDunApn();
    781                             if (dunSetting != null &&
    782                                     dunSetting.equals(apnContext.getApnSetting())) {
    783                                 if (DBG) log("tearing down dedicated DUN connection");
    784                                 // we need to tear it down - we brought it up just for dun and
    785                                 // other people are camped on it and now dun is done.  We need
    786                                 // to stop using it and let the normal apn list get used to find
    787                                 // connections for the remaining desired connections
    788                                 disconnectAll = true;
    789                             }
    790                         }
    791                         if (DBG) {
    792                             log("cleanUpConnection: tearing down" + (disconnectAll ? " all" :""));
    793                         }
    794                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, apnContext);
    795                         if (disconnectAll) {
    796                             apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg);
    797                         } else {
    798                             apnContext.getDcAc()
    799                                 .tearDown(apnContext, apnContext.getReason(), msg);
    800                         }
    801                         apnContext.setState(DctConstants.State.DISCONNECTING);
    802                     }
    803                 } else {
    804                     // apn is connected but no reference to dcac.
    805                     // Should not be happen, but reset the state in case.
    806                     apnContext.setState(DctConstants.State.IDLE);
    807                     mPhone.notifyDataConnection(apnContext.getReason(),
    808                                                 apnContext.getApnType());
    809                 }
    810             }
    811         } else {
    812             // force clean up the data connection.
    813             if (dcac != null) dcac.reqReset();
    814             apnContext.setState(DctConstants.State.IDLE);
    815             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
    816             apnContext.setDataConnectionAc(null);
    817         }
    818 
    819         // Make sure reconnection alarm is cleaned up if there is no ApnContext
    820         // associated to the connection.
    821         if (dcac != null) {
    822             cancelReconnectAlarm(apnContext);
    823         }
    824         if (DBG) {
    825             log("cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason() +
    826                     " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc());
    827         }
    828     }
    829 
    830     /**
    831      * Cancels the alarm associated with apnContext.
    832      *
    833      * @param apnContext on which the alarm should be stopped.
    834      */
    835     private void cancelReconnectAlarm(ApnContext apnContext) {
    836         if (apnContext == null) return;
    837 
    838         PendingIntent intent = apnContext.getReconnectIntent();
    839 
    840         if (intent != null) {
    841                 AlarmManager am =
    842                     (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
    843                 am.cancel(intent);
    844                 apnContext.setReconnectIntent(null);
    845         }
    846     }
    847 
    848     /**
    849      * @param types comma delimited list of APN types
    850      * @return array of APN types
    851      */
    852     private String[] parseTypes(String types) {
    853         String[] result;
    854         // If unset, set to DEFAULT.
    855         if (types == null || types.equals("")) {
    856             result = new String[1];
    857             result[0] = PhoneConstants.APN_TYPE_ALL;
    858         } else {
    859             result = types.split(",");
    860         }
    861         return result;
    862     }
    863 
    864    private boolean imsiMatches(String imsiDB, String imsiSIM) {
    865         // Note: imsiDB value has digit number or 'x' character for seperating USIM information
    866         // for MVNO operator. And then digit number is matched at same order and 'x' character
    867         // could replace by any digit number.
    868         // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator,
    869         //     that means first 6 digits, 8th and 9th digit
    870         //     should be set in USIM for GG Operator.
    871         int len = imsiDB.length();
    872         int idxCompare = 0;
    873 
    874         if (len <= 0) return false;
    875         if (len > imsiSIM.length()) return false;
    876 
    877         for (int idx=0; idx<len; idx++) {
    878             char c = imsiDB.charAt(idx);
    879             if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) {
    880                 continue;
    881             } else {
    882                 return false;
    883             }
    884         }
    885         return true;
    886     }
    887 
    888     private boolean mvnoMatches(IccRecords r, String mvno_type, String mvno_match_data) {
    889         if (mvno_type.equalsIgnoreCase("spn")) {
    890             if ((r.getServiceProviderName() != null) &&
    891                     r.getServiceProviderName().equalsIgnoreCase(mvno_match_data)) {
    892                 return true;
    893             }
    894         } else if (mvno_type.equalsIgnoreCase("imsi")) {
    895             String imsiSIM = r.getIMSI();
    896             if ((imsiSIM != null) && imsiMatches(mvno_match_data, imsiSIM)) {
    897                 return true;
    898             }
    899         } else if (mvno_type.equalsIgnoreCase("gid")) {
    900             String gid1 = r.getGid1();
    901             if ((gid1 != null) && gid1.substring(0,
    902                     mvno_match_data.length()).equalsIgnoreCase(mvno_match_data)) {
    903                 return true;
    904             }
    905         }
    906         return false;
    907     }
    908 
    909     private ApnSetting makeApnSetting(Cursor cursor) {
    910         String[] types = parseTypes(
    911                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
    912         ApnSetting apn = new ApnSetting(
    913                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
    914                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
    915                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
    916                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
    917                 NetworkUtils.trimV4AddrZeros(
    918                         cursor.getString(
    919                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
    920                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
    921                 NetworkUtils.trimV4AddrZeros(
    922                         cursor.getString(
    923                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
    924                 NetworkUtils.trimV4AddrZeros(
    925                         cursor.getString(
    926                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
    927                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
    928                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
    929                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
    930                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
    931                 types,
    932                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
    933                 cursor.getString(cursor.getColumnIndexOrThrow(
    934                         Telephony.Carriers.ROAMING_PROTOCOL)),
    935                 cursor.getInt(cursor.getColumnIndexOrThrow(
    936                         Telephony.Carriers.CARRIER_ENABLED)) == 1,
    937                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)));
    938         return apn;
    939     }
    940 
    941     private ArrayList<ApnSetting> createApnList(Cursor cursor) {
    942         ArrayList<ApnSetting> result = new ArrayList<ApnSetting>();
    943         IccRecords r = mIccRecords.get();
    944 
    945         if (cursor.moveToFirst()) {
    946             String mvnoType = null;
    947             String mvnoMatchData = null;
    948             do {
    949                 String cursorMvnoType = cursor.getString(
    950                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE));
    951                 String cursorMvnoMatchData = cursor.getString(
    952                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA));
    953                 if (mvnoType != null) {
    954                     if (mvnoType.equals(cursorMvnoType) &&
    955                             mvnoMatchData.equals(cursorMvnoMatchData)) {
    956                         result.add(makeApnSetting(cursor));
    957                     }
    958                 } else {
    959                     // no mvno match yet
    960                     if (mvnoMatches(r, cursorMvnoType, cursorMvnoMatchData)) {
    961                         // first match - toss out non-mvno data
    962                         result.clear();
    963                         mvnoType = cursorMvnoType;
    964                         mvnoMatchData = cursorMvnoMatchData;
    965                         result.add(makeApnSetting(cursor));
    966                     } else {
    967                         // add only non-mvno data
    968                         if (cursorMvnoType.equals("")) {
    969                             result.add(makeApnSetting(cursor));
    970                         }
    971                     }
    972                 }
    973             } while (cursor.moveToNext());
    974         }
    975         if (DBG) log("createApnList: X result=" + result);
    976         return result;
    977     }
    978 
    979     private boolean dataConnectionNotInUse(DcAsyncChannel dcac) {
    980         if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac);
    981         for (ApnContext apnContext : mApnContexts.values()) {
    982             if (apnContext.getDcAc() == dcac) {
    983                 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext);
    984                 return false;
    985             }
    986         }
    987         // TODO: Fix retry handling so free DataConnections have empty apnlists.
    988         // Probably move retry handling into DataConnections and reduce complexity
    989         // of DCT.
    990         if (DBG) log("dataConnectionNotInUse: tearDownAll");
    991         dcac.tearDownAll("No connection", null);
    992         if (DBG) log("dataConnectionNotInUse: not in use return true");
    993         return true;
    994     }
    995 
    996     private DcAsyncChannel findFreeDataConnection() {
    997         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
    998             if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
    999                 if (DBG) {
   1000                     log("findFreeDataConnection: found free DataConnection=" +
   1001                         " dcac=" + dcac);
   1002                 }
   1003                 return dcac;
   1004             }
   1005         }
   1006         log("findFreeDataConnection: NO free DataConnection");
   1007         return null;
   1008     }
   1009 
   1010     private boolean setupData(ApnContext apnContext) {
   1011         if (DBG) log("setupData: apnContext=" + apnContext);
   1012         ApnSetting apnSetting;
   1013         DcAsyncChannel dcac;
   1014 
   1015         int profileId = getApnProfileID(apnContext.getApnType());
   1016         apnSetting = apnContext.getNextWaitingApn();
   1017         if (apnSetting == null) {
   1018             if (DBG) log("setupData: return for no apn found!");
   1019             return false;
   1020         }
   1021 
   1022         dcac = checkForCompatibleConnectedApnContext(apnContext);
   1023         if (dcac != null) {
   1024             // Get the dcacApnSetting for the connection we want to share.
   1025             ApnSetting dcacApnSetting = dcac.getApnSettingSync();
   1026             if (dcacApnSetting != null) {
   1027                 // Setting is good, so use it.
   1028                 apnSetting = dcacApnSetting;
   1029             }
   1030         }
   1031         if (dcac == null) {
   1032             dcac = findFreeDataConnection();
   1033 
   1034             if (dcac == null) {
   1035                 dcac = createDataConnection();
   1036             }
   1037 
   1038             if (dcac == null) {
   1039                 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
   1040                 return false;
   1041             }
   1042         }
   1043         if (DBG) log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting);
   1044 
   1045         apnContext.setDataConnectionAc(dcac);
   1046         apnContext.setApnSetting(apnSetting);
   1047         apnContext.setState(DctConstants.State.CONNECTING);
   1048         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
   1049 
   1050         Message msg = obtainMessage();
   1051         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
   1052         msg.obj = apnContext;
   1053         dcac.bringUp(apnContext, getInitialMaxRetry(), profileId, msg);
   1054 
   1055         if (DBG) log("setupData: initing!");
   1056         return true;
   1057     }
   1058 
   1059     /**
   1060      * Handles changes to the APN database.
   1061      */
   1062     private void onApnChanged() {
   1063         DctConstants.State overallState = getOverallState();
   1064         boolean isDisconnected = (overallState == DctConstants.State.IDLE ||
   1065                 overallState == DctConstants.State.FAILED);
   1066 
   1067         if (mPhone instanceof GSMPhone) {
   1068             // The "current" may no longer be valid.  MMS depends on this to send properly. TBD
   1069             ((GSMPhone)mPhone).updateCurrentCarrierInProvider();
   1070         }
   1071 
   1072         // TODO: It'd be nice to only do this if the changed entrie(s)
   1073         // match the current operator.
   1074         if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
   1075         createAllApnList();
   1076         cleanUpAllConnections(!isDisconnected, Phone.REASON_APN_CHANGED);
   1077         if (isDisconnected) {
   1078             setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
   1079         }
   1080     }
   1081 
   1082     /**
   1083      * @param cid Connection id provided from RIL.
   1084      * @return DataConnectionAc associated with specified cid.
   1085      */
   1086     private DcAsyncChannel findDataConnectionAcByCid(int cid) {
   1087         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
   1088             if (dcac.getCidSync() == cid) {
   1089                 return dcac;
   1090             }
   1091         }
   1092         return null;
   1093     }
   1094 
   1095     /**
   1096      * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST
   1097      * or RIL_UNSOL_DATA_CALL_LIST_CHANGED
   1098      */
   1099     private void onDataStateChanged (AsyncResult ar) {
   1100         ArrayList<DataCallResponse> dataCallStates;
   1101 
   1102         if (DBG) log("onDataStateChanged(ar): E");
   1103         dataCallStates = (ArrayList<DataCallResponse>)(ar.result);
   1104 
   1105         if (ar.exception != null) {
   1106             // This is probably "radio not available" or something
   1107             // of that sort. If so, the whole connection is going
   1108             // to come down soon anyway
   1109             if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
   1110             return;
   1111         }
   1112         if (DBG) log("onDataStateChanged(ar): DataCallResponse size=" + dataCallStates.size());
   1113 
   1114         // Create a hash map to store the dataCallState of each DataConnectionAc
   1115         HashMap<DataCallResponse, DcAsyncChannel> dataCallStateToDcac;
   1116         dataCallStateToDcac = new HashMap<DataCallResponse, DcAsyncChannel>();
   1117         for (DataCallResponse dataCallState : dataCallStates) {
   1118             DcAsyncChannel dcac = findDataConnectionAcByCid(dataCallState.cid);
   1119 
   1120             if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
   1121         }
   1122 
   1123         // Check if we should start or stop polling, by looking
   1124         // for dormant and active connections.
   1125         boolean isAnyDataCallDormant = false;
   1126         boolean isAnyDataCallActive = false;
   1127         for (DataCallResponse newState : dataCallStates) {
   1128             if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_UP) isAnyDataCallActive = true;
   1129             if (newState.active == DATA_CONNECTION_ACTIVE_PH_LINK_DOWN) isAnyDataCallDormant = true;
   1130         }
   1131 
   1132         if (isAnyDataCallDormant && !isAnyDataCallActive) {
   1133             // There is no way to indicate link activity per APN right now. So
   1134             // Link Activity will be considered dormant only when all data calls
   1135             // are dormant.
   1136             // If a single data call is in dormant state and none of the data
   1137             // calls are active broadcast overall link state as dormant.
   1138             mActivity = DctConstants.Activity.DORMANT;
   1139             if (DBG) {
   1140                 log("onDataStateChanged: Data Activity updated to DORMANT. stopNetStatePoll");
   1141             }
   1142             stopNetStatPoll();
   1143         } else {
   1144             mActivity = DctConstants.Activity.NONE;
   1145             if (DBG) {
   1146                 log("onDataStateChanged: Data Activity updated to NONE. " +
   1147                          "isAnyDataCallActive = " + isAnyDataCallActive +
   1148                          " isAnyDataCallDormant = " + isAnyDataCallDormant);
   1149             }
   1150             if (isAnyDataCallActive) startNetStatPoll();
   1151         }
   1152 
   1153         if (DBG) log("onDataStateChanged(ar): X");
   1154     }
   1155 
   1156     // TODO: For multiple Active APNs not exactly sure how to do this.
   1157     @Override
   1158     protected void gotoIdleAndNotifyDataConnection(String reason) {
   1159         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
   1160         notifyDataConnection(reason);
   1161         mActiveApn = null;
   1162     }
   1163 
   1164     @Override
   1165     protected void restartRadio() {
   1166         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
   1167         cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
   1168         mPhone.getServiceStateTracker().powerOffRadioSafely(this);
   1169         /* Note: no need to call setRadioPower(true).  Assuming the desired
   1170          * radio power state is still ON (as tracked by ServiceStateTracker),
   1171          * ServiceStateTracker will call setRadioPower when it receives the
   1172          * RADIO_STATE_CHANGED notification for the power off.  And if the
   1173          * desired power state has changed in the interim, we don't want to
   1174          * override it with an unconditional power on.
   1175          */
   1176 
   1177         int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
   1178         SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1));
   1179     }
   1180 
   1181     /**
   1182      * Return true if data connection need to be setup after disconnected due to
   1183      * reason.
   1184      *
   1185      * @param reason the reason why data is disconnected
   1186      * @return true if try setup data connection is need for this reason
   1187      */
   1188     private boolean retryAfterDisconnected(String reason) {
   1189         boolean retry = true;
   1190 
   1191         if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
   1192             retry = false;
   1193         }
   1194         return retry;
   1195     }
   1196 
   1197     private void startAlarmForReconnect(int delay, ApnContext apnContext) {
   1198         String apnType = apnContext.getApnType();
   1199 
   1200         Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType);
   1201         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
   1202         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType);
   1203 
   1204         if (DBG) {
   1205             log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction()
   1206                     + " apn=" + apnContext);
   1207         }
   1208 
   1209         PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
   1210                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
   1211         apnContext.setReconnectIntent(alarmIntent);
   1212         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   1213                 SystemClock.elapsedRealtime() + delay, alarmIntent);
   1214     }
   1215 
   1216     private void startAlarmForRestartTrySetup(int delay, ApnContext apnContext) {
   1217         String apnType = apnContext.getApnType();
   1218         Intent intent = new Intent(INTENT_RESTART_TRYSETUP_ALARM + "." + apnType);
   1219         intent.putExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE, apnType);
   1220 
   1221         if (DBG) {
   1222             log("startAlarmForRestartTrySetup: delay=" + delay + " action=" + intent.getAction()
   1223                     + " apn=" + apnContext);
   1224         }
   1225         PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
   1226                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
   1227         apnContext.setReconnectIntent(alarmIntent);
   1228         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   1229                 SystemClock.elapsedRealtime() + delay, alarmIntent);
   1230     }
   1231 
   1232     private void notifyNoData(DcFailCause lastFailCauseCode,
   1233                               ApnContext apnContext) {
   1234         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
   1235         if (lastFailCauseCode.isPermanentFail()
   1236             && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
   1237             mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
   1238         }
   1239     }
   1240 
   1241     private void onRecordsLoaded() {
   1242         if (DBG) log("onRecordsLoaded: createAllApnList");
   1243         createAllApnList();
   1244         if (mPhone.mCi.getRadioState().isOn()) {
   1245             if (DBG) log("onRecordsLoaded: notifying data availability");
   1246             notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
   1247         }
   1248         setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
   1249     }
   1250 
   1251     @Override
   1252     protected void onSetDependencyMet(String apnType, boolean met) {
   1253         // don't allow users to tweak hipri to work around default dependency not met
   1254         if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return;
   1255 
   1256         ApnContext apnContext = mApnContexts.get(apnType);
   1257         if (apnContext == null) {
   1258             loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
   1259                     apnType + ", " + met + ")");
   1260             return;
   1261         }
   1262         applyNewState(apnContext, apnContext.isEnabled(), met);
   1263         if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) {
   1264             // tie actions on default to similar actions on HIPRI regarding dependencyMet
   1265             apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI);
   1266             if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met);
   1267         }
   1268     }
   1269 
   1270     private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
   1271         boolean cleanup = false;
   1272         boolean trySetup = false;
   1273         if (DBG) {
   1274             log("applyNewState(" + apnContext.getApnType() + ", " + enabled +
   1275                     "(" + apnContext.isEnabled() + "), " + met + "(" +
   1276                     apnContext.getDependencyMet() +"))");
   1277         }
   1278         if (apnContext.isReady()) {
   1279             if (enabled && met) {
   1280                 DctConstants.State state = apnContext.getState();
   1281                 switch(state) {
   1282                     case CONNECTING:
   1283                     case SCANNING:
   1284                     case CONNECTED:
   1285                     case DISCONNECTING:
   1286                         // We're "READY" and active so just return
   1287                         if (DBG) log("applyNewState: 'ready' so return");
   1288                         return;
   1289                     case IDLE:
   1290                         // fall through: this is unexpected but if it happens cleanup and try setup
   1291                     case FAILED:
   1292                     case RETRYING: {
   1293                         // We're "READY" but not active so disconnect (cleanup = true) and
   1294                         // connect (trySetup = true) to be sure we retry the connection.
   1295                         trySetup = true;
   1296                         apnContext.setReason(Phone.REASON_DATA_ENABLED);
   1297                         break;
   1298                     }
   1299                 }
   1300             } else if (!enabled) {
   1301                 apnContext.setReason(Phone.REASON_DATA_DISABLED);
   1302             } else {
   1303                 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
   1304             }
   1305             cleanup = true;
   1306         } else {
   1307             if (enabled && met) {
   1308                 if (apnContext.isEnabled()) {
   1309                     apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
   1310                 } else {
   1311                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
   1312                 }
   1313                 if (apnContext.getState() == DctConstants.State.FAILED) {
   1314                     apnContext.setState(DctConstants.State.IDLE);
   1315                 }
   1316                 trySetup = true;
   1317             }
   1318         }
   1319         apnContext.setEnabled(enabled);
   1320         apnContext.setDependencyMet(met);
   1321         if (cleanup) cleanUpConnection(true, apnContext);
   1322         if (trySetup) trySetupData(apnContext);
   1323     }
   1324 
   1325     private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) {
   1326         String apnType = apnContext.getApnType();
   1327         ApnSetting dunSetting = null;
   1328 
   1329         if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) {
   1330             dunSetting = fetchDunApn();
   1331         }
   1332         if (DBG) {
   1333             log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext );
   1334         }
   1335 
   1336         DcAsyncChannel potentialDcac = null;
   1337         ApnContext potentialApnCtx = null;
   1338         for (ApnContext curApnCtx : mApnContexts.values()) {
   1339             DcAsyncChannel curDcac = curApnCtx.getDcAc();
   1340             if (curDcac != null) {
   1341                 ApnSetting apnSetting = curApnCtx.getApnSetting();
   1342                 if (dunSetting != null) {
   1343                     if (dunSetting.equals(apnSetting)) {
   1344                         switch (curApnCtx.getState()) {
   1345                             case CONNECTED:
   1346                                 if (DBG) {
   1347                                     log("checkForCompatibleConnectedApnContext:"
   1348                                             + " found dun conn=" + curDcac
   1349                                             + " curApnCtx=" + curApnCtx);
   1350                                 }
   1351                                 return curDcac;
   1352                             case RETRYING:
   1353                             case CONNECTING:
   1354                                 potentialDcac = curDcac;
   1355                                 potentialApnCtx = curApnCtx;
   1356                             default:
   1357                                 // Not connected, potential unchanged
   1358                                 break;
   1359                         }
   1360                     }
   1361                 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) {
   1362                     switch (curApnCtx.getState()) {
   1363                         case CONNECTED:
   1364                             if (DBG) {
   1365                                 log("checkForCompatibleConnectedApnContext:"
   1366                                         + " found canHandle conn=" + curDcac
   1367                                         + " curApnCtx=" + curApnCtx);
   1368                             }
   1369                             return curDcac;
   1370                         case RETRYING:
   1371                         case CONNECTING:
   1372                             potentialDcac = curDcac;
   1373                             potentialApnCtx = curApnCtx;
   1374                         default:
   1375                             // Not connected, potential unchanged
   1376                             break;
   1377                     }
   1378                 }
   1379             } else {
   1380                 if (VDBG) {
   1381                     log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx);
   1382                 }
   1383             }
   1384         }
   1385         if (potentialDcac != null) {
   1386             if (DBG) {
   1387                 log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac
   1388                         + " curApnCtx=" + potentialApnCtx);
   1389             }
   1390             return potentialDcac;
   1391         }
   1392 
   1393         if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext);
   1394         return null;
   1395     }
   1396 
   1397     @Override
   1398     protected void onEnableApn(int apnId, int enabled) {
   1399         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
   1400         if (apnContext == null) {
   1401             loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
   1402             return;
   1403         }
   1404         // TODO change our retry manager to use the appropriate numbers for the new APN
   1405         if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
   1406         applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
   1407     }
   1408 
   1409     @Override
   1410     // TODO: We shouldnt need this.
   1411     protected boolean onTrySetupData(String reason) {
   1412         if (DBG) log("onTrySetupData: reason=" + reason);
   1413         setupDataOnConnectableApns(reason);
   1414         return true;
   1415     }
   1416 
   1417     protected boolean onTrySetupData(ApnContext apnContext) {
   1418         if (DBG) log("onTrySetupData: apnContext=" + apnContext);
   1419         return trySetupData(apnContext);
   1420     }
   1421 
   1422     @Override
   1423     protected void onRoamingOff() {
   1424         if (DBG) log("onRoamingOff");
   1425 
   1426         if (mUserDataEnabled == false) return;
   1427 
   1428         if (getDataOnRoamingEnabled() == false) {
   1429             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
   1430             setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
   1431         } else {
   1432             notifyDataConnection(Phone.REASON_ROAMING_OFF);
   1433         }
   1434     }
   1435 
   1436     @Override
   1437     protected void onRoamingOn() {
   1438         if (mUserDataEnabled == false) return;
   1439 
   1440         if (getDataOnRoamingEnabled()) {
   1441             if (DBG) log("onRoamingOn: setup data on roaming");
   1442             setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
   1443             notifyDataConnection(Phone.REASON_ROAMING_ON);
   1444         } else {
   1445             if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
   1446             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
   1447             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
   1448         }
   1449     }
   1450 
   1451     @Override
   1452     protected void onRadioAvailable() {
   1453         if (DBG) log("onRadioAvailable");
   1454         if (mPhone.getSimulatedRadioControl() != null) {
   1455             // Assume data is connected on the simulator
   1456             // FIXME  this can be improved
   1457             // setState(DctConstants.State.CONNECTED);
   1458             notifyDataConnection(null);
   1459 
   1460             log("onRadioAvailable: We're on the simulator; assuming data is connected");
   1461         }
   1462 
   1463         IccRecords r = mIccRecords.get();
   1464         if (r != null && r.getRecordsLoaded()) {
   1465             notifyOffApnsOfAvailability(null);
   1466         }
   1467 
   1468         if (getOverallState() != DctConstants.State.IDLE) {
   1469             cleanUpConnection(true, null);
   1470         }
   1471     }
   1472 
   1473     @Override
   1474     protected void onRadioOffOrNotAvailable() {
   1475         // Make sure our reconnect delay starts at the initial value
   1476         // next time the radio comes on
   1477 
   1478         mReregisterOnReconnectFailure = false;
   1479 
   1480         if (mPhone.getSimulatedRadioControl() != null) {
   1481             // Assume data is connected on the simulator
   1482             // FIXME  this can be improved
   1483             log("We're on the simulator; assuming radio off is meaningless");
   1484         } else {
   1485             if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
   1486             cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
   1487         }
   1488         notifyOffApnsOfAvailability(null);
   1489     }
   1490 
   1491     @Override
   1492     protected void completeConnection(ApnContext apnContext) {
   1493         boolean isProvApn = apnContext.isProvisioningApn();
   1494 
   1495         if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext);
   1496 
   1497         if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) {
   1498             if (DBG) {
   1499                 log("completeConnection: MOBILE_PROVISIONING_ACTION url="
   1500                         + mProvisioningUrl);
   1501             }
   1502             Intent newIntent =
   1503                     new Intent(Intent.ACTION_VIEW, Uri.parse(mProvisioningUrl));
   1504             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
   1505                     Intent.FLAG_ACTIVITY_NEW_TASK);
   1506             try {
   1507                 mPhone.getContext().startActivity(newIntent);
   1508             } catch (ActivityNotFoundException e) {
   1509                 loge("completeConnection: startActivityAsUser failed" + e);
   1510             }
   1511         }
   1512         mIsProvisioning = false;
   1513         mProvisioningUrl = null;
   1514 
   1515         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
   1516         startNetStatPoll();
   1517         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
   1518     }
   1519 
   1520     /**
   1521      * A SETUP (aka bringUp) has completed, possibly with an error. If
   1522      * there is an error this method will call {@link #onDataSetupCompleteError}.
   1523      */
   1524     @Override
   1525     protected void onDataSetupComplete(AsyncResult ar) {
   1526 
   1527         DcFailCause cause = DcFailCause.UNKNOWN;
   1528         boolean handleError = false;
   1529         ApnContext apnContext = null;
   1530 
   1531         if(ar.userObj instanceof ApnContext){
   1532             apnContext = (ApnContext)ar.userObj;
   1533         } else {
   1534             throw new RuntimeException("onDataSetupComplete: No apnContext");
   1535         }
   1536 
   1537         if (ar.exception == null) {
   1538             DcAsyncChannel dcac = apnContext.getDcAc();
   1539 
   1540             if (RADIO_TESTS) {
   1541                 // Note: To change radio.test.onDSC.null.dcac from command line you need to
   1542                 // adb root and adb remount and from the command line you can only change the
   1543                 // value to 1 once. To change it a second time you can reboot or execute
   1544                 // adb shell stop and then adb shell start. The command line to set the value is:
   1545                 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
   1546                 ContentResolver cr = mPhone.getContext().getContentResolver();
   1547                 String radioTestProperty = "radio.test.onDSC.null.dcac";
   1548                 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {
   1549                     log("onDataSetupComplete: " + radioTestProperty +
   1550                             " is true, set dcac to null and reset property to false");
   1551                     dcac = null;
   1552                     Settings.System.putInt(cr, radioTestProperty, 0);
   1553                     log("onDataSetupComplete: " + radioTestProperty + "=" +
   1554                             Settings.System.getInt(mPhone.getContext().getContentResolver(),
   1555                                     radioTestProperty, -1));
   1556                 }
   1557             }
   1558             if (dcac == null) {
   1559                 log("onDataSetupComplete: no connection to DC, handle as error");
   1560                 cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
   1561                 handleError = true;
   1562             } else {
   1563                 ApnSetting apn = apnContext.getApnSetting();
   1564                 if (DBG) {
   1565                     log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn));
   1566                 }
   1567                 if (apn != null && apn.proxy != null && apn.proxy.length() != 0) {
   1568                     try {
   1569                         String port = apn.port;
   1570                         if (TextUtils.isEmpty(port)) port = "8080";
   1571                         ProxyProperties proxy = new ProxyProperties(apn.proxy,
   1572                                 Integer.parseInt(port), null);
   1573                         dcac.setLinkPropertiesHttpProxySync(proxy);
   1574                     } catch (NumberFormatException e) {
   1575                         loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
   1576                                 apn.port + "): " + e);
   1577                     }
   1578                 }
   1579 
   1580                 // everything is setup
   1581                 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
   1582                     SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
   1583                     if (mCanSetPreferApn && mPreferredApn == null) {
   1584                         if (DBG) log("onDataSetupComplete: PREFERED APN is null");
   1585                         mPreferredApn = apn;
   1586                         if (mPreferredApn != null) {
   1587                             setPreferredApn(mPreferredApn.id);
   1588                         }
   1589                     }
   1590                 } else {
   1591                     SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
   1592                 }
   1593 
   1594                 // A connection is setup
   1595                 apnContext.setState(DctConstants.State.CONNECTED);
   1596                 boolean isProvApn = apnContext.isProvisioningApn();
   1597                 if ((!isProvApn) || mIsProvisioning) {
   1598                     // Complete the connection normally notifying the world we're connected.
   1599                     // We do this if this isn't a special provisioning apn or if we've been
   1600                     // told its time to provision.
   1601                     completeConnection(apnContext);
   1602                 } else {
   1603                     // This is a provisioning APN that we're reporting as connected. Later
   1604                     // when the user desires to upgrade this to a "default" connection,
   1605                     // mIsProvisioning == true, we'll go through the code path above.
   1606                     // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING
   1607                     // is sent to the DCT.
   1608                     if (DBG) {
   1609                         log("onDataSetupComplete: successful, BUT send connected to prov apn as"
   1610                                 + " mIsProvisioning:" + mIsProvisioning + " == false"
   1611                                 + " && (isProvisioningApn:" + isProvApn + " == true");
   1612                     }
   1613 
   1614                     Intent intent = new Intent(
   1615                             TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
   1616                     intent.putExtra(PhoneConstants.DATA_APN_KEY, apnContext.getApnSetting().apn);
   1617                     intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnContext.getApnType());
   1618 
   1619                     String apnType = apnContext.getApnType();
   1620                     LinkProperties linkProperties = getLinkProperties(apnType);
   1621                     if (linkProperties != null) {
   1622                         intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
   1623                         String iface = linkProperties.getInterfaceName();
   1624                         if (iface != null) {
   1625                             intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
   1626                         }
   1627                     }
   1628                     LinkCapabilities linkCapabilities = getLinkCapabilities(apnType);
   1629                     if (linkCapabilities != null) {
   1630                         intent.putExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
   1631                     }
   1632 
   1633                     mPhone.getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
   1634                 }
   1635                 if (DBG) {
   1636                     log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
   1637                         + ", reason:" + apnContext.getReason());
   1638                 }
   1639             }
   1640         } else {
   1641             cause = (DcFailCause) (ar.result);
   1642             if (DBG) {
   1643                 ApnSetting apn = apnContext.getApnSetting();
   1644                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
   1645                         (apn == null ? "unknown" : apn.apn), cause));
   1646             }
   1647             if (cause.isEventLoggable()) {
   1648                 // Log this failure to the Event Logs.
   1649                 int cid = getCellLocationId();
   1650                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
   1651                         cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType());
   1652             }
   1653 
   1654             // Count permanent failures and remove the APN we just tried
   1655             if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
   1656 
   1657             apnContext.removeWaitingApn(apnContext.getApnSetting());
   1658             if (DBG) {
   1659                 log(String.format("onDataSetupComplete: WaitingApns.size=%d" +
   1660                         " WaitingApnsPermFailureCountDown=%d",
   1661                         apnContext.getWaitingApns().size(),
   1662                         apnContext.getWaitingApnsPermFailCount()));
   1663             }
   1664             handleError = true;
   1665         }
   1666 
   1667         if (handleError) {
   1668             onDataSetupCompleteError(ar);
   1669         }
   1670     }
   1671 
   1672     /**
   1673      * @return number of milli-seconds to delay between trying apns'
   1674      */
   1675     private int getApnDelay() {
   1676         if (mFailFast) {
   1677             return SystemProperties.getInt("persist.radio.apn_ff_delay",
   1678                     APN_FAIL_FAST_DELAY_DEFAULT_MILLIS);
   1679         } else {
   1680             return SystemProperties.getInt("persist.radio.apn_delay", APN_DELAY_DEFAULT_MILLIS);
   1681         }
   1682     }
   1683 
   1684     /**
   1685      * Error has occurred during the SETUP {aka bringUP} request and the DCT
   1686      * should either try the next waiting APN or start over from the
   1687      * beginning if the list is empty. Between each SETUP request there will
   1688      * be a delay defined by {@link #getApnDelay()}.
   1689      */
   1690     @Override
   1691     protected void onDataSetupCompleteError(AsyncResult ar) {
   1692         String reason = "";
   1693         ApnContext apnContext = null;
   1694 
   1695         if(ar.userObj instanceof ApnContext){
   1696             apnContext = (ApnContext)ar.userObj;
   1697         } else {
   1698             throw new RuntimeException("onDataSetupCompleteError: No apnContext");
   1699         }
   1700 
   1701         // See if there are more APN's to try
   1702         if (apnContext.getWaitingApns().isEmpty()) {
   1703             apnContext.setState(DctConstants.State.FAILED);
   1704             mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
   1705 
   1706             apnContext.setDataConnectionAc(null);
   1707 
   1708             if (apnContext.getWaitingApnsPermFailCount() == 0) {
   1709                 if (DBG) {
   1710                     log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
   1711                 }
   1712             } else {
   1713                 if (DBG) {
   1714                     log("onDataSetupComplete: Not all APN's had permanent failures, short delay");
   1715                 }
   1716                 startAlarmForRestartTrySetup(getApnDelay(), apnContext);
   1717             }
   1718         } else {
   1719             if (DBG) log("onDataSetupComplete: Try next APN");
   1720             apnContext.setState(DctConstants.State.SCANNING);
   1721             // Wait a bit before trying the next APN, so that
   1722             // we're not tying up the RIL command channel
   1723             startAlarmForReconnect(getApnDelay(), apnContext);
   1724         }
   1725     }
   1726 
   1727     /**
   1728      * Called when EVENT_DISCONNECT_DONE is received.
   1729      */
   1730     @Override
   1731     protected void onDisconnectDone(int connId, AsyncResult ar) {
   1732         ApnContext apnContext = null;
   1733 
   1734         if (ar.userObj instanceof ApnContext) {
   1735             apnContext = (ApnContext) ar.userObj;
   1736         } else {
   1737             loge("onDisconnectDone: Invalid ar in onDisconnectDone, ignore");
   1738             return;
   1739         }
   1740 
   1741         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
   1742         apnContext.setState(DctConstants.State.IDLE);
   1743 
   1744         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
   1745 
   1746         // if all data connection are gone, check whether Airplane mode request was
   1747         // pending.
   1748         if (isDisconnected()) {
   1749             if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
   1750                 // Radio will be turned off. No need to retry data setup
   1751                 apnContext.setApnSetting(null);
   1752                 apnContext.setDataConnectionAc(null);
   1753                 return;
   1754             }
   1755         }
   1756 
   1757         // If APN is still enabled, try to bring it back up automatically
   1758         if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) {
   1759             SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
   1760             // Wait a bit before trying the next APN, so that
   1761             // we're not tying up the RIL command channel.
   1762             // This also helps in any external dependency to turn off the context.
   1763             startAlarmForReconnect(getApnDelay(), apnContext);
   1764         } else {
   1765             apnContext.setApnSetting(null);
   1766             apnContext.setDataConnectionAc(null);
   1767         }
   1768     }
   1769 
   1770     /**
   1771      * Called when EVENT_DISCONNECT_DC_RETRYING is received.
   1772      */
   1773     @Override
   1774     protected void onDisconnectDcRetrying(int connId, AsyncResult ar) {
   1775         // We could just do this in DC!!!
   1776         ApnContext apnContext = null;
   1777 
   1778         if (ar.userObj instanceof ApnContext) {
   1779             apnContext = (ApnContext) ar.userObj;
   1780         } else {
   1781             loge("onDisconnectDcRetrying: Invalid ar in onDisconnectDone, ignore");
   1782             return;
   1783         }
   1784 
   1785         apnContext.setState(DctConstants.State.RETRYING);
   1786         if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
   1787 
   1788         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
   1789     }
   1790 
   1791     protected void onPollPdp() {
   1792         if (getOverallState() == DctConstants.State.CONNECTED) {
   1793             // only poll when connected
   1794             mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
   1795             sendMessageDelayed(obtainMessage(DctConstants.EVENT_POLL_PDP), POLL_PDP_MILLIS);
   1796         }
   1797     }
   1798 
   1799     @Override
   1800     protected void onVoiceCallStarted() {
   1801         if (DBG) log("onVoiceCallStarted");
   1802         mInVoiceCall = true;
   1803         if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
   1804             if (DBG) log("onVoiceCallStarted stop polling");
   1805             stopNetStatPoll();
   1806             stopDataStallAlarm();
   1807             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
   1808         }
   1809     }
   1810 
   1811     @Override
   1812     protected void onVoiceCallEnded() {
   1813         if (DBG) log("onVoiceCallEnded");
   1814         mInVoiceCall = false;
   1815         if (isConnected()) {
   1816             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
   1817                 startNetStatPoll();
   1818                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
   1819                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
   1820             } else {
   1821                 // clean slate after call end.
   1822                 resetPollStats();
   1823             }
   1824         }
   1825         // reset reconnect timer
   1826         setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED);
   1827     }
   1828 
   1829     @Override
   1830     protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
   1831         if (DBG) log("onCleanUpConnection");
   1832         ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
   1833         if (apnContext != null) {
   1834             apnContext.setReason(reason);
   1835             cleanUpConnection(tearDown, apnContext);
   1836         }
   1837     }
   1838 
   1839     @Override
   1840     protected boolean isConnected() {
   1841         for (ApnContext apnContext : mApnContexts.values()) {
   1842             if (apnContext.getState() == DctConstants.State.CONNECTED) {
   1843                 // At least one context is connected, return true
   1844                 return true;
   1845             }
   1846         }
   1847         // There are not any contexts connected, return false
   1848         return false;
   1849     }
   1850 
   1851     @Override
   1852     public boolean isDisconnected() {
   1853         for (ApnContext apnContext : mApnContexts.values()) {
   1854             if (!apnContext.isDisconnected()) {
   1855                 // At least one context was not disconnected return false
   1856                 return false;
   1857             }
   1858         }
   1859         // All contexts were disconnected so return true
   1860         return true;
   1861     }
   1862 
   1863     @Override
   1864     protected void notifyDataConnection(String reason) {
   1865         if (DBG) log("notifyDataConnection: reason=" + reason);
   1866         for (ApnContext apnContext : mApnContexts.values()) {
   1867             if (apnContext.isReady()) {
   1868                 if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType());
   1869                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
   1870                         apnContext.getApnType());
   1871             }
   1872         }
   1873         notifyOffApnsOfAvailability(reason);
   1874     }
   1875 
   1876     /**
   1877      * Based on the sim operator numeric, create a list for all possible
   1878      * Data Connections and setup the preferredApn.
   1879      */
   1880     private void createAllApnList() {
   1881         mAllApnSettings = new ArrayList<ApnSetting>();
   1882         IccRecords r = mIccRecords.get();
   1883         String operator = (r != null) ? r.getOperatorNumeric() : "";
   1884         if (operator != null) {
   1885             String selection = "numeric = '" + operator + "'";
   1886             // query only enabled apn.
   1887             // carrier_enabled : 1 means enabled apn, 0 disabled apn.
   1888             selection += " and carrier_enabled = 1";
   1889             if (DBG) log("createAllApnList: selection=" + selection);
   1890 
   1891             Cursor cursor = mPhone.getContext().getContentResolver().query(
   1892                     Telephony.Carriers.CONTENT_URI, null, selection, null, null);
   1893 
   1894             if (cursor != null) {
   1895                 if (cursor.getCount() > 0) {
   1896                     mAllApnSettings = createApnList(cursor);
   1897                 }
   1898                 cursor.close();
   1899             }
   1900         }
   1901 
   1902         if (mAllApnSettings.isEmpty()) {
   1903             if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
   1904             mPreferredApn = null;
   1905             // TODO: What is the right behavior?
   1906             //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
   1907         } else {
   1908             mPreferredApn = getPreferredApn();
   1909             if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
   1910                 mPreferredApn = null;
   1911                 setPreferredApn(-1);
   1912             }
   1913             if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
   1914         }
   1915         if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
   1916     }
   1917 
   1918     /** Return the DC AsyncChannel for the new data connection */
   1919     private DcAsyncChannel createDataConnection() {
   1920         if (DBG) log("createDataConnection E");
   1921 
   1922         int id = mUniqueIdGenerator.getAndIncrement();
   1923         DataConnection conn = DataConnection.makeDataConnection(mPhone, id,
   1924                                                 this, mDcTesterFailBringUpAll, mDcc);
   1925         mDataConnections.put(id, conn);
   1926         DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
   1927         int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
   1928         if (status == AsyncChannel.STATUS_SUCCESSFUL) {
   1929             mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
   1930         } else {
   1931             loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
   1932         }
   1933 
   1934         if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
   1935         return dcac;
   1936     }
   1937 
   1938     private void destroyDataConnections() {
   1939         if(mDataConnections != null) {
   1940             if (DBG) log("destroyDataConnections: clear mDataConnectionList");
   1941             mDataConnections.clear();
   1942         } else {
   1943             if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
   1944         }
   1945     }
   1946 
   1947     /**
   1948      * Build a list of APNs to be used to create PDP's.
   1949      *
   1950      * @param requestedApnType
   1951      * @return waitingApns list to be used to create PDP
   1952      *          error when waitingApns.isEmpty()
   1953      */
   1954     private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) {
   1955         if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType);
   1956         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
   1957 
   1958         if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) {
   1959             ApnSetting dun = fetchDunApn();
   1960             if (dun != null) {
   1961                 apnList.add(dun);
   1962                 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
   1963                 return apnList;
   1964             }
   1965         }
   1966 
   1967         IccRecords r = mIccRecords.get();
   1968         String operator = (r != null) ? r.getOperatorNumeric() : "";
   1969         int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
   1970 
   1971         // This is a workaround for a bug (7305641) where we don't failover to other
   1972         // suitable APNs if our preferred APN fails.  On prepaid ATT sims we need to
   1973         // failover to a provisioning APN, but once we've used their default data
   1974         // connection we are locked to it for life.  This change allows ATT devices
   1975         // to say they don't want to use preferred at all.
   1976         boolean usePreferred = true;
   1977         try {
   1978             usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android.
   1979                     internal.R.bool.config_dontPreferApn);
   1980         } catch (Resources.NotFoundException e) {
   1981             if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true");
   1982             usePreferred = true;
   1983         }
   1984         if (DBG) {
   1985             log("buildWaitingApns: usePreferred=" + usePreferred
   1986                     + " canSetPreferApn=" + mCanSetPreferApn
   1987                     + " mPreferredApn=" + mPreferredApn
   1988                     + " operator=" + operator + " radioTech=" + radioTech
   1989                     + " IccRecords r=" + r);
   1990         }
   1991 
   1992         if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
   1993                 mPreferredApn.canHandleType(requestedApnType)) {
   1994             if (DBG) {
   1995                 log("buildWaitingApns: Preferred APN:" + operator + ":"
   1996                         + mPreferredApn.numeric + ":" + mPreferredApn);
   1997             }
   1998             if (mPreferredApn.numeric.equals(operator)) {
   1999                 if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) {
   2000                     apnList.add(mPreferredApn);
   2001                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
   2002                     return apnList;
   2003                 } else {
   2004                     if (DBG) log("buildWaitingApns: no preferred APN");
   2005                     setPreferredApn(-1);
   2006                     mPreferredApn = null;
   2007                 }
   2008             } else {
   2009                 if (DBG) log("buildWaitingApns: no preferred APN");
   2010                 setPreferredApn(-1);
   2011                 mPreferredApn = null;
   2012             }
   2013         }
   2014         if (mAllApnSettings != null) {
   2015             if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
   2016             for (ApnSetting apn : mAllApnSettings) {
   2017                 if (DBG) log("buildWaitingApns: apn=" + apn);
   2018                 if (apn.canHandleType(requestedApnType)) {
   2019                     if (apn.bearer == 0 || apn.bearer == radioTech) {
   2020                         if (DBG) log("buildWaitingApns: adding apn=" + apn.toString());
   2021                         apnList.add(apn);
   2022                     } else {
   2023                         if (DBG) {
   2024                             log("buildWaitingApns: bearer:" + apn.bearer + " != "
   2025                                     + "radioTech:" + radioTech);
   2026                         }
   2027                     }
   2028                 } else {
   2029                 if (DBG) {
   2030                     log("buildWaitingApns: couldn't handle requesedApnType="
   2031                             + requestedApnType);
   2032                 }
   2033             }
   2034             }
   2035         } else {
   2036             loge("mAllApnSettings is empty!");
   2037         }
   2038         if (DBG) log("buildWaitingApns: X apnList=" + apnList);
   2039         return apnList;
   2040     }
   2041 
   2042     private String apnListToString (ArrayList<ApnSetting> apns) {
   2043         StringBuilder result = new StringBuilder();
   2044         for (int i = 0, size = apns.size(); i < size; i++) {
   2045             result.append('[')
   2046                   .append(apns.get(i).toString())
   2047                   .append(']');
   2048         }
   2049         return result.toString();
   2050     }
   2051 
   2052     private void setPreferredApn(int pos) {
   2053         if (!mCanSetPreferApn) {
   2054             log("setPreferredApn: X !canSEtPreferApn");
   2055             return;
   2056         }
   2057 
   2058         log("setPreferredApn: delete");
   2059         ContentResolver resolver = mPhone.getContext().getContentResolver();
   2060         resolver.delete(PREFERAPN_NO_UPDATE_URI, null, null);
   2061 
   2062         if (pos >= 0) {
   2063             log("setPreferredApn: insert");
   2064             ContentValues values = new ContentValues();
   2065             values.put(APN_ID, pos);
   2066             resolver.insert(PREFERAPN_NO_UPDATE_URI, values);
   2067         }
   2068     }
   2069 
   2070     private ApnSetting getPreferredApn() {
   2071         if (mAllApnSettings.isEmpty()) {
   2072             log("getPreferredApn: X not found mAllApnSettings.isEmpty");
   2073             return null;
   2074         }
   2075 
   2076         Cursor cursor = mPhone.getContext().getContentResolver().query(
   2077                 PREFERAPN_NO_UPDATE_URI, new String[] { "_id", "name", "apn" },
   2078                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
   2079 
   2080         if (cursor != null) {
   2081             mCanSetPreferApn = true;
   2082         } else {
   2083             mCanSetPreferApn = false;
   2084         }
   2085         log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
   2086                 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));
   2087 
   2088         if (mCanSetPreferApn && cursor.getCount() > 0) {
   2089             int pos;
   2090             cursor.moveToFirst();
   2091             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
   2092             for(ApnSetting p : mAllApnSettings) {
   2093                 log("getPreferredApn: apnSetting=" + p);
   2094                 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
   2095                     log("getPreferredApn: X found apnSetting" + p);
   2096                     cursor.close();
   2097                     return p;
   2098                 }
   2099             }
   2100         }
   2101 
   2102         if (cursor != null) {
   2103             cursor.close();
   2104         }
   2105 
   2106         log("getPreferredApn: X not found");
   2107         return null;
   2108     }
   2109 
   2110     @Override
   2111     public void handleMessage (Message msg) {
   2112         if (DBG) log("handleMessage msg=" + msg);
   2113 
   2114         if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
   2115             loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
   2116             return;
   2117         }
   2118 
   2119         switch (msg.what) {
   2120             case DctConstants.EVENT_RECORDS_LOADED:
   2121                 onRecordsLoaded();
   2122                 break;
   2123 
   2124             case DctConstants.EVENT_DATA_CONNECTION_DETACHED:
   2125                 onDataConnectionDetached();
   2126                 break;
   2127 
   2128             case DctConstants.EVENT_DATA_CONNECTION_ATTACHED:
   2129                 onDataConnectionAttached();
   2130                 break;
   2131 
   2132             case DctConstants.EVENT_DATA_STATE_CHANGED:
   2133                 onDataStateChanged((AsyncResult) msg.obj);
   2134                 break;
   2135 
   2136             case DctConstants.EVENT_POLL_PDP:
   2137                 onPollPdp();
   2138                 break;
   2139 
   2140             case DctConstants.EVENT_DO_RECOVERY:
   2141                 doRecovery();
   2142                 break;
   2143 
   2144             case DctConstants.EVENT_APN_CHANGED:
   2145                 onApnChanged();
   2146                 break;
   2147 
   2148             case DctConstants.EVENT_PS_RESTRICT_ENABLED:
   2149                 /**
   2150                  * We don't need to explicitly to tear down the PDP context
   2151                  * when PS restricted is enabled. The base band will deactive
   2152                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
   2153                  * But we should stop the network polling and prevent reset PDP.
   2154                  */
   2155                 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
   2156                 stopNetStatPoll();
   2157                 stopDataStallAlarm();
   2158                 mIsPsRestricted = true;
   2159                 break;
   2160 
   2161             case DctConstants.EVENT_PS_RESTRICT_DISABLED:
   2162                 /**
   2163                  * When PS restrict is removed, we need setup PDP connection if
   2164                  * PDP connection is down.
   2165                  */
   2166                 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
   2167                 mIsPsRestricted  = false;
   2168                 if (isConnected()) {
   2169                     startNetStatPoll();
   2170                     startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
   2171                 } else {
   2172                     // TODO: Should all PDN states be checked to fail?
   2173                     if (mState == DctConstants.State.FAILED) {
   2174                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
   2175                         mReregisterOnReconnectFailure = false;
   2176                     }
   2177                     trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, PhoneConstants.APN_TYPE_DEFAULT);
   2178                 }
   2179                 break;
   2180 
   2181             case DctConstants.EVENT_TRY_SETUP_DATA:
   2182                 if (msg.obj instanceof ApnContext) {
   2183                     onTrySetupData((ApnContext)msg.obj);
   2184                 } else if (msg.obj instanceof String) {
   2185                     onTrySetupData((String)msg.obj);
   2186                 } else {
   2187                     loge("EVENT_TRY_SETUP request w/o apnContext or String");
   2188                 }
   2189                 break;
   2190 
   2191             case DctConstants.EVENT_CLEAN_UP_CONNECTION:
   2192                 boolean tearDown = (msg.arg1 == 0) ? false : true;
   2193                 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
   2194                 if (msg.obj instanceof ApnContext) {
   2195                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
   2196                 } else {
   2197                     loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context, call super");
   2198                     super.handleMessage(msg);
   2199                 }
   2200                 break;
   2201 
   2202             default:
   2203                 // handle the message in the super class DataConnectionTracker
   2204                 super.handleMessage(msg);
   2205                 break;
   2206         }
   2207     }
   2208 
   2209     protected int getApnProfileID(String apnType) {
   2210         if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) {
   2211             return RILConstants.DATA_PROFILE_IMS;
   2212         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) {
   2213             return RILConstants.DATA_PROFILE_FOTA;
   2214         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) {
   2215             return RILConstants.DATA_PROFILE_CBS;
   2216         } else {
   2217             return RILConstants.DATA_PROFILE_DEFAULT;
   2218         }
   2219     }
   2220 
   2221     private int getCellLocationId() {
   2222         int cid = -1;
   2223         CellLocation loc = mPhone.getCellLocation();
   2224 
   2225         if (loc != null) {
   2226             if (loc instanceof GsmCellLocation) {
   2227                 cid = ((GsmCellLocation)loc).getCid();
   2228             } else if (loc instanceof CdmaCellLocation) {
   2229                 cid = ((CdmaCellLocation)loc).getBaseStationId();
   2230             }
   2231         }
   2232         return cid;
   2233     }
   2234 
   2235     @Override
   2236     protected void onUpdateIcc() {
   2237         if (mUiccController == null ) {
   2238             return;
   2239         }
   2240 
   2241         IccRecords newIccRecords = mUiccController.getIccRecords(UiccController.APP_FAM_3GPP);
   2242 
   2243         IccRecords r = mIccRecords.get();
   2244         if (r != newIccRecords) {
   2245             if (r != null) {
   2246                 log("Removing stale icc objects.");
   2247                 r.unregisterForRecordsLoaded(this);
   2248                 mIccRecords.set(null);
   2249             }
   2250             if (newIccRecords != null) {
   2251                 log("New records found");
   2252                 mIccRecords.set(newIccRecords);
   2253                 newIccRecords.registerForRecordsLoaded(
   2254                         this, DctConstants.EVENT_RECORDS_LOADED, null);
   2255             }
   2256         }
   2257     }
   2258 
   2259     @Override
   2260     protected void log(String s) {
   2261         Rlog.d(LOG_TAG, s);
   2262     }
   2263 
   2264     @Override
   2265     protected void loge(String s) {
   2266         Rlog.e(LOG_TAG, s);
   2267     }
   2268 
   2269     @Override
   2270     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2271         pw.println("DataConnectionTracker extends:");
   2272         super.dump(fd, pw, args);
   2273         pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure);
   2274         pw.println(" canSetPreferApn=" + mCanSetPreferApn);
   2275         pw.println(" mApnObserver=" + mApnObserver);
   2276         pw.println(" getOverallState=" + getOverallState());
   2277         pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap);
   2278     }
   2279 }
   2280