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