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