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.BroadcastReceiver;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.SharedPreferences;
     27 import android.database.ContentObserver;
     28 import android.net.LinkCapabilities;
     29 import android.net.LinkProperties;
     30 import android.net.NetworkInfo;
     31 import android.net.TrafficStats;
     32 import android.net.wifi.WifiManager;
     33 import android.os.AsyncResult;
     34 import android.os.Bundle;
     35 import android.os.Handler;
     36 import android.os.HandlerThread;
     37 import android.os.Message;
     38 import android.os.Messenger;
     39 import android.os.SystemClock;
     40 import android.os.SystemProperties;
     41 import android.preference.PreferenceManager;
     42 import android.provider.Settings;
     43 import android.provider.Settings.SettingNotFoundException;
     44 import android.telephony.TelephonyManager;
     45 import android.text.TextUtils;
     46 import android.util.EventLog;
     47 import android.telephony.Rlog;
     48 
     49 import com.android.internal.R;
     50 import com.android.internal.telephony.DctConstants;
     51 import com.android.internal.telephony.EventLogTags;
     52 import com.android.internal.telephony.Phone;
     53 import com.android.internal.telephony.PhoneBase;
     54 import com.android.internal.telephony.PhoneConstants;
     55 import com.android.internal.telephony.uicc.IccRecords;
     56 import com.android.internal.telephony.uicc.UiccController;
     57 import com.android.internal.util.AsyncChannel;
     58 
     59 import java.io.FileDescriptor;
     60 import java.io.PrintWriter;
     61 import java.util.ArrayList;
     62 import java.util.HashMap;
     63 import java.util.Map.Entry;
     64 import java.util.Set;
     65 import java.util.concurrent.ConcurrentHashMap;
     66 import java.util.concurrent.atomic.AtomicInteger;
     67 import java.util.concurrent.atomic.AtomicReference;
     68 
     69 /**
     70  * {@hide}
     71  */
     72 public abstract class DcTrackerBase extends Handler {
     73     protected static final boolean DBG = true;
     74     protected static final boolean VDBG = false; // STOPSHIP if true
     75     protected static final boolean VDBG_STALL = true; // STOPSHIP if true
     76     protected static final boolean RADIO_TESTS = false;
     77 
     78     /**
     79      * Constants for the data connection activity:
     80      * physical link down/up
     81      */
     82     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0;
     83     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1;
     84     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
     85 
     86     /** Delay between APN attempts.
     87         Note the property override mechanism is there just for testing purpose only. */
     88     protected static final int APN_DELAY_DEFAULT_MILLIS = 20000;
     89 
     90     /** Delay between APN attempts when in fail fast mode */
     91     protected static final int APN_FAIL_FAST_DELAY_DEFAULT_MILLIS = 3000;
     92 
     93     AlarmManager mAlarmManager;
     94 
     95     protected Object mDataEnabledLock = new Object();
     96 
     97     // responds to the setInternalDataEnabled call - used internally to turn off data
     98     // for example during emergency calls
     99     protected boolean mInternalDataEnabled = true;
    100 
    101     // responds to public (user) API to enable/disable data use
    102     // independent of mInternalDataEnabled and requests for APN access
    103     // persisted
    104     protected boolean mUserDataEnabled = true;
    105 
    106     // TODO: move away from static state once 5587429 is fixed.
    107     protected static boolean sPolicyDataEnabled = true;
    108 
    109     private boolean[] mDataEnabled = new boolean[DctConstants.APN_NUM_TYPES];
    110 
    111     private int mEnabledCount = 0;
    112 
    113     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
    114     protected String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
    115 
    116     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
    117     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
    118         + "5000,10000,20000,40000,80000:5000,160000:5000,"
    119         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
    120 
    121     /** Retry configuration for secondary networks: 4 tries in 20 sec */
    122     protected static final String SECONDARY_DATA_RETRY_CONFIG =
    123             "max_retries=3, 5000, 5000, 5000";
    124 
    125     /** Slow poll when attempting connection recovery. */
    126     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
    127     /** Default max failure count before attempting to network re-registration. */
    128     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
    129 
    130     /**
    131      * After detecting a potential connection problem, this is the max number
    132      * of subsequent polls before attempting recovery.
    133      */
    134     protected static final int NO_RECV_POLL_LIMIT = 24;
    135     // 1 sec. default polling interval when screen is on.
    136     protected static final int POLL_NETSTAT_MILLIS = 1000;
    137     // 10 min. default polling interval when screen is off.
    138     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
    139     // 2 min for round trip time
    140     protected static final int POLL_LONGEST_RTT = 120 * 1000;
    141     // Default sent packets without ack which triggers initial recovery steps
    142     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
    143     // how long to wait before switching back to default APN
    144     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
    145     // system property that can override the above value
    146     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
    147     // represents an invalid IP address
    148     protected static final String NULL_IP = "0.0.0.0";
    149 
    150     // Default for the data stall alarm while non-aggressive stall detection
    151     protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
    152     // Default for the data stall alarm for aggressive stall detection
    153     protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
    154     // If attempt is less than this value we're doing first level recovery
    155     protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1;
    156     // Tag for tracking stale alarms
    157     protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
    158 
    159     protected static final boolean DATA_STALL_SUSPECTED = true;
    160     protected static final boolean DATA_STALL_NOT_SUSPECTED = false;
    161 
    162     protected String RADIO_RESET_PROPERTY = "gsm.radioreset";
    163 
    164     protected static final String INTENT_RECONNECT_ALARM =
    165             "com.android.internal.telephony.data-reconnect";
    166     protected static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
    167     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
    168             "reconnect_alarm_extra_reason";
    169 
    170     protected static final String INTENT_RESTART_TRYSETUP_ALARM =
    171             "com.android.internal.telephony.data-restart-trysetup";
    172     protected static final String INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE =
    173             "restart_trysetup_alarm_extra_type";
    174 
    175     protected static final String INTENT_DATA_STALL_ALARM =
    176             "com.android.internal.telephony.data-stall";
    177 
    178 
    179 
    180     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
    181 
    182     protected DcTesterFailBringUpAll mDcTesterFailBringUpAll;
    183     protected DcController mDcc;
    184 
    185     // member variables
    186     protected PhoneBase mPhone;
    187     protected UiccController mUiccController;
    188     protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
    189     protected DctConstants.Activity mActivity = DctConstants.Activity.NONE;
    190     protected DctConstants.State mState = DctConstants.State.IDLE;
    191     protected Handler mDataConnectionTracker = null;
    192 
    193     protected long mTxPkts;
    194     protected long mRxPkts;
    195     protected int mNetStatPollPeriod;
    196     protected boolean mNetStatPollEnabled = false;
    197 
    198     protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
    199     // Used to track stale data stall alarms.
    200     protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
    201     // The current data stall alarm intent
    202     protected PendingIntent mDataStallAlarmIntent = null;
    203     // Number of packets sent since the last received packet
    204     protected long mSentSinceLastRecv;
    205     // Controls when a simple recovery attempt it to be tried
    206     protected int mNoRecvPollCount = 0;
    207     // True if data stall detection is enabled
    208     protected volatile boolean mDataStallDetectionEnabled = true;
    209 
    210     protected volatile boolean mFailFast = false;
    211 
    212     // True when in voice call
    213     protected boolean mInVoiceCall = false;
    214 
    215     // wifi connection status will be updated by sticky intent
    216     protected boolean mIsWifiConnected = false;
    217 
    218     /** Intent sent when the reconnect alarm fires. */
    219     protected PendingIntent mReconnectIntent = null;
    220 
    221     /** CID of active data connection */
    222     protected int mCidActive;
    223 
    224     // When false we will not auto attach and manually attaching is required.
    225     protected boolean mAutoAttachOnCreation = false;
    226 
    227     // State of screen
    228     // (TODO: Reconsider tying directly to screen, maybe this is
    229     //        really a lower power mode")
    230     protected boolean mIsScreenOn = true;
    231 
    232     /** Allows the generation of unique Id's for DataConnection objects */
    233     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
    234 
    235     /** The data connections. */
    236     protected HashMap<Integer, DataConnection> mDataConnections =
    237         new HashMap<Integer, DataConnection>();
    238 
    239     /** The data connection async channels */
    240     protected HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap =
    241         new HashMap<Integer, DcAsyncChannel>();
    242 
    243     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
    244     protected HashMap<String, Integer> mApnToDataConnectionId =
    245                                     new HashMap<String, Integer>();
    246 
    247     /** Phone.APN_TYPE_* ===> ApnContext */
    248     protected ConcurrentHashMap<String, ApnContext> mApnContexts =
    249                                     new ConcurrentHashMap<String, ApnContext>();
    250 
    251     /* Currently active APN */
    252     protected ApnSetting mActiveApn;
    253 
    254     /** allApns holds all apns */
    255     protected ArrayList<ApnSetting> mAllApnSettings = null;
    256 
    257     /** preferred apn */
    258     protected ApnSetting mPreferredApn = null;
    259 
    260     /** Is packet service restricted by network */
    261     protected boolean mIsPsRestricted = false;
    262 
    263     /* Once disposed dont handle any messages */
    264     protected boolean mIsDisposed = false;
    265 
    266     protected ContentResolver mResolver;
    267 
    268     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
    269     {
    270         @Override
    271         public void onReceive(Context context, Intent intent)
    272         {
    273             String action = intent.getAction();
    274             if (DBG) log("onReceive: action=" + action);
    275             if (action.equals(Intent.ACTION_SCREEN_ON)) {
    276                 mIsScreenOn = true;
    277                 stopNetStatPoll();
    278                 startNetStatPoll();
    279                 restartDataStallAlarm();
    280             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    281                 mIsScreenOn = false;
    282                 stopNetStatPoll();
    283                 startNetStatPoll();
    284                 restartDataStallAlarm();
    285             } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
    286                 if (DBG) log("Reconnect alarm. Previous state was " + mState);
    287                 onActionIntentReconnectAlarm(intent);
    288             } else if (action.startsWith(INTENT_RESTART_TRYSETUP_ALARM)) {
    289                 if (DBG) log("Restart trySetup alarm");
    290                 onActionIntentRestartTrySetupAlarm(intent);
    291             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
    292                 onActionIntentDataStallAlarm(intent);
    293             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    294                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
    295                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    296                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
    297                 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected);
    298             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
    299                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
    300                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
    301 
    302                 if (!enabled) {
    303                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
    304                     // quit and won't report disconnected until next enabling.
    305                     mIsWifiConnected = false;
    306                 }
    307                 if (DBG) log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled
    308                         + " mIsWifiConnected=" + mIsWifiConnected);
    309             }
    310         }
    311     };
    312 
    313     private Runnable mPollNetStat = new Runnable()
    314     {
    315         @Override
    316         public void run() {
    317             updateDataActivity();
    318 
    319             if (mIsScreenOn) {
    320                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
    321                         Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
    322             } else {
    323                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
    324                         Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
    325                         POLL_NETSTAT_SCREEN_OFF_MILLIS);
    326             }
    327 
    328             if (mNetStatPollEnabled) {
    329                 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
    330             }
    331         }
    332     };
    333 
    334     private class DataRoamingSettingObserver extends ContentObserver {
    335 
    336         public DataRoamingSettingObserver(Handler handler, Context context) {
    337             super(handler);
    338             mResolver = context.getContentResolver();
    339         }
    340 
    341         public void register() {
    342             mResolver.registerContentObserver(
    343                     Settings.Global.getUriFor(Settings.Global.DATA_ROAMING), false, this);
    344         }
    345 
    346         public void unregister() {
    347             mResolver.unregisterContentObserver(this);
    348         }
    349 
    350         @Override
    351         public void onChange(boolean selfChange) {
    352             // already running on mPhone handler thread
    353             if (mPhone.getServiceState().getRoaming()) {
    354                 sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
    355             }
    356         }
    357     }
    358     private final DataRoamingSettingObserver mDataRoamingSettingObserver;
    359 
    360     /**
    361      * The Initial MaxRetry sent to a DataConnection as a parameter
    362      * to DataConnectionAc.bringUp. This value can be defined at compile
    363      * time using the SystemProperty Settings.Global.DCT_INITIAL_MAX_RETRY
    364      * and at runtime using gservices to change Settings.Global.DCT_INITIAL_MAX_RETRY.
    365      */
    366     private static final int DEFAULT_MDC_INITIAL_RETRY = 1;
    367     protected int getInitialMaxRetry() {
    368         if (mFailFast) {
    369             return 0;
    370         }
    371         // Get default value from system property or use DEFAULT_MDC_INITIAL_RETRY
    372         int value = SystemProperties.getInt(
    373                 Settings.Global.MDC_INITIAL_MAX_RETRY, DEFAULT_MDC_INITIAL_RETRY);
    374 
    375         // Check if its been overridden
    376         return Settings.Global.getInt(mResolver,
    377                 Settings.Global.MDC_INITIAL_MAX_RETRY, value);
    378     }
    379 
    380     /**
    381      * Maintain the sum of transmit and receive packets.
    382      *
    383      * The packet counts are initialized and reset to -1 and
    384      * remain -1 until they can be updated.
    385      */
    386     public class TxRxSum {
    387         public long txPkts;
    388         public long rxPkts;
    389 
    390         public TxRxSum() {
    391             reset();
    392         }
    393 
    394         public TxRxSum(long txPkts, long rxPkts) {
    395             this.txPkts = txPkts;
    396             this.rxPkts = rxPkts;
    397         }
    398 
    399         public TxRxSum(TxRxSum sum) {
    400             txPkts = sum.txPkts;
    401             rxPkts = sum.rxPkts;
    402         }
    403 
    404         public void reset() {
    405             txPkts = -1;
    406             rxPkts = -1;
    407         }
    408 
    409         @Override
    410         public String toString() {
    411             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
    412         }
    413 
    414         public void updateTxRxSum() {
    415             this.txPkts = TrafficStats.getMobileTcpTxPackets();
    416             this.rxPkts = TrafficStats.getMobileTcpRxPackets();
    417         }
    418     }
    419 
    420     protected void onActionIntentReconnectAlarm(Intent intent) {
    421         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
    422         String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
    423 
    424         ApnContext apnContext = mApnContexts.get(apnType);
    425 
    426         if (DBG) {
    427             log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
    428                     " apnType=" + apnType + " apnContext=" + apnContext +
    429                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
    430         }
    431 
    432         if ((apnContext != null) && (apnContext.isEnabled())) {
    433             apnContext.setReason(reason);
    434             DctConstants.State apnContextState = apnContext.getState();
    435             if (DBG) {
    436                 log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
    437             }
    438             if ((apnContextState == DctConstants.State.FAILED)
    439                     || (apnContextState == DctConstants.State.IDLE)) {
    440                 if (DBG) {
    441                     log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
    442                 }
    443                 DcAsyncChannel dcac = apnContext.getDcAc();
    444                 if (dcac != null) {
    445                     dcac.tearDown(apnContext, "", null);
    446                 }
    447                 apnContext.setDataConnectionAc(null);
    448                 apnContext.setState(DctConstants.State.IDLE);
    449             } else {
    450                 if (DBG) log("onActionIntentReconnectAlarm: keep associated");
    451             }
    452             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
    453             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
    454 
    455             apnContext.setReconnectIntent(null);
    456         }
    457     }
    458 
    459     protected void onActionIntentRestartTrySetupAlarm(Intent intent) {
    460         String apnType = intent.getStringExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE);
    461         ApnContext apnContext = mApnContexts.get(apnType);
    462         if (DBG) {
    463             log("onActionIntentRestartTrySetupAlarm: mState=" + mState +
    464                     " apnType=" + apnType + " apnContext=" + apnContext +
    465                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
    466         }
    467         sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
    468     }
    469 
    470     protected void onActionIntentDataStallAlarm(Intent intent) {
    471         if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
    472         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
    473                 intent.getAction());
    474         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
    475         sendMessage(msg);
    476     }
    477 
    478     /**
    479      * Default constructor
    480      */
    481     protected DcTrackerBase(PhoneBase phone) {
    482         super();
    483         if (DBG) log("DCT.constructor");
    484         mPhone = phone;
    485         mResolver = mPhone.getContext().getContentResolver();
    486         mUiccController = UiccController.getInstance();
    487         mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
    488         mAlarmManager =
    489                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
    490 
    491 
    492         IntentFilter filter = new IntentFilter();
    493         filter.addAction(Intent.ACTION_SCREEN_ON);
    494         filter.addAction(Intent.ACTION_SCREEN_OFF);
    495         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    496         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    497         filter.addAction(INTENT_DATA_STALL_ALARM);
    498 
    499         mUserDataEnabled = Settings.Global.getInt(
    500                 mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, 1) == 1;
    501 
    502         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
    503 
    504         // This preference tells us 1) initial condition for "dataEnabled",
    505         // and 2) whether the RIL will setup the baseband to auto-PS attach.
    506 
    507         mDataEnabled[DctConstants.APN_DEFAULT_ID] =
    508                 SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,true);
    509         if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) {
    510             mEnabledCount++;
    511         }
    512 
    513         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
    514         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
    515 
    516         // Watch for changes to Settings.Global.DATA_ROAMING
    517         mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone, mPhone.getContext());
    518         mDataRoamingSettingObserver.register();
    519 
    520         HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
    521         dcHandlerThread.start();
    522         Handler dcHandler = new Handler(dcHandlerThread.getLooper());
    523         mDcc = DcController.makeDcc(mPhone, this, dcHandler);
    524         mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
    525     }
    526 
    527     public void dispose() {
    528         if (DBG) log("DCT.dispose");
    529         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
    530             dcac.disconnect();
    531         }
    532         mDataConnectionAcHashMap.clear();
    533         mIsDisposed = true;
    534         mPhone.getContext().unregisterReceiver(mIntentReceiver);
    535         mUiccController.unregisterForIccChanged(this);
    536         mDataRoamingSettingObserver.unregister();
    537         mDcc.dispose();
    538         mDcTesterFailBringUpAll.dispose();
    539     }
    540 
    541     public DctConstants.Activity getActivity() {
    542         return mActivity;
    543     }
    544 
    545     public boolean isApnTypeActive(String type) {
    546         // TODO: support simultaneous with List instead
    547         if (PhoneConstants.APN_TYPE_DUN.equals(type)) {
    548             ApnSetting dunApn = fetchDunApn();
    549             if (dunApn != null) {
    550                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
    551             }
    552         }
    553         return mActiveApn != null && mActiveApn.canHandleType(type);
    554     }
    555 
    556     protected ApnSetting fetchDunApn() {
    557         if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
    558             log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
    559             return null;
    560         }
    561         Context c = mPhone.getContext();
    562         String apnData = Settings.Global.getString(c.getContentResolver(),
    563                 Settings.Global.TETHER_DUN_APN);
    564         ApnSetting dunSetting = ApnSetting.fromString(apnData);
    565         if (dunSetting != null) {
    566             if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
    567             return dunSetting;
    568         }
    569 
    570         apnData = c.getResources().getString(R.string.config_tether_apndata);
    571         dunSetting = ApnSetting.fromString(apnData);
    572         if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + dunSetting);
    573         return dunSetting;
    574     }
    575 
    576     public String[] getActiveApnTypes() {
    577         String[] result;
    578         if (mActiveApn != null) {
    579             result = mActiveApn.types;
    580         } else {
    581             result = new String[1];
    582             result[0] = PhoneConstants.APN_TYPE_DEFAULT;
    583         }
    584         return result;
    585     }
    586 
    587     /** TODO: See if we can remove */
    588     public String getActiveApnString(String apnType) {
    589         String result = null;
    590         if (mActiveApn != null) {
    591             result = mActiveApn.apn;
    592         }
    593         return result;
    594     }
    595 
    596     /**
    597      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
    598      */
    599     public void setDataOnRoamingEnabled(boolean enabled) {
    600         if (getDataOnRoamingEnabled() != enabled) {
    601             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    602             Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, enabled ? 1 : 0);
    603             // will trigger handleDataOnRoamingChange() through observer
    604         }
    605     }
    606 
    607     /**
    608      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
    609      */
    610     public boolean getDataOnRoamingEnabled() {
    611         try {
    612             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    613             return Settings.Global.getInt(resolver, Settings.Global.DATA_ROAMING) != 0;
    614         } catch (SettingNotFoundException snfe) {
    615             return false;
    616         }
    617     }
    618 
    619     // abstract methods
    620     protected abstract void restartRadio();
    621     protected abstract void log(String s);
    622     protected abstract void loge(String s);
    623     protected abstract boolean isDataAllowed();
    624     protected abstract boolean isApnTypeAvailable(String type);
    625     public    abstract DctConstants.State getState(String apnType);
    626     protected abstract void setState(DctConstants.State s);
    627     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
    628 
    629     protected abstract boolean onTrySetupData(String reason);
    630     protected abstract void onRoamingOff();
    631     protected abstract void onRoamingOn();
    632     protected abstract void onRadioAvailable();
    633     protected abstract void onRadioOffOrNotAvailable();
    634     protected abstract void onDataSetupComplete(AsyncResult ar);
    635     protected abstract void onDataSetupCompleteError(AsyncResult ar);
    636     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
    637     protected abstract void onDisconnectDcRetrying(int connId, AsyncResult ar);
    638     protected abstract void onVoiceCallStarted();
    639     protected abstract void onVoiceCallEnded();
    640     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
    641     protected abstract void onCleanUpAllConnections(String cause);
    642     public abstract boolean isDataPossible(String apnType);
    643     protected abstract void onUpdateIcc();
    644 
    645     @Override
    646     public void handleMessage(Message msg) {
    647         switch (msg.what) {
    648             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    649                 log("DISCONNECTED_CONNECTED: msg=" + msg);
    650                 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj;
    651                 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());
    652                 dcac.disconnected();
    653                 break;
    654             }
    655             case DctConstants.EVENT_ENABLE_NEW_APN:
    656                 onEnableApn(msg.arg1, msg.arg2);
    657                 break;
    658 
    659             case DctConstants.EVENT_TRY_SETUP_DATA:
    660                 String reason = null;
    661                 if (msg.obj instanceof String) {
    662                     reason = (String) msg.obj;
    663                 }
    664                 onTrySetupData(reason);
    665                 break;
    666 
    667             case DctConstants.EVENT_DATA_STALL_ALARM:
    668                 onDataStallAlarm(msg.arg1);
    669                 break;
    670 
    671             case DctConstants.EVENT_ROAMING_OFF:
    672                 onRoamingOff();
    673                 break;
    674 
    675             case DctConstants.EVENT_ROAMING_ON:
    676                 onRoamingOn();
    677                 break;
    678 
    679             case DctConstants.EVENT_RADIO_AVAILABLE:
    680                 onRadioAvailable();
    681                 break;
    682 
    683             case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
    684                 onRadioOffOrNotAvailable();
    685                 break;
    686 
    687             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
    688                 mCidActive = msg.arg1;
    689                 onDataSetupComplete((AsyncResult) msg.obj);
    690                 break;
    691 
    692             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
    693                 onDataSetupCompleteError((AsyncResult) msg.obj);
    694                 break;
    695 
    696             case DctConstants.EVENT_DISCONNECT_DONE:
    697                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
    698                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
    699                 break;
    700 
    701             case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
    702                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
    703                 onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj);
    704                 break;
    705 
    706             case DctConstants.EVENT_VOICE_CALL_STARTED:
    707                 onVoiceCallStarted();
    708                 break;
    709 
    710             case DctConstants.EVENT_VOICE_CALL_ENDED:
    711                 onVoiceCallEnded();
    712                 break;
    713 
    714             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: {
    715                 onCleanUpAllConnections((String) msg.obj);
    716                 break;
    717             }
    718             case DctConstants.EVENT_CLEAN_UP_CONNECTION: {
    719                 boolean tearDown = (msg.arg1 == 0) ? false : true;
    720                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
    721                 break;
    722             }
    723             case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
    724                 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
    725                 onSetInternalDataEnabled(enabled);
    726                 break;
    727             }
    728             case DctConstants.EVENT_RESET_DONE: {
    729                 if (DBG) log("EVENT_RESET_DONE");
    730                 onResetDone((AsyncResult) msg.obj);
    731                 break;
    732             }
    733             case DctConstants.CMD_SET_USER_DATA_ENABLE: {
    734                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
    735                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
    736                 onSetUserDataEnabled(enabled);
    737                 break;
    738             }
    739             case DctConstants.CMD_SET_DEPENDENCY_MET: {
    740                 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false;
    741                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
    742                 Bundle bundle = msg.getData();
    743                 if (bundle != null) {
    744                     String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
    745                     if (apnType != null) {
    746                         onSetDependencyMet(apnType, met);
    747                     }
    748                 }
    749                 break;
    750             }
    751             case DctConstants.CMD_SET_POLICY_DATA_ENABLE: {
    752                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
    753                 onSetPolicyDataEnabled(enabled);
    754                 break;
    755             }
    756             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
    757                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
    758                 if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled);
    759                 if (mFailFast != enabled) {
    760                     mFailFast = enabled;
    761                     mDataStallDetectionEnabled = !enabled;
    762                     if (mDataStallDetectionEnabled
    763                             && (getOverallState() == DctConstants.State.CONNECTED)
    764                             && (!mInVoiceCall ||
    765                                     mPhone.getServiceStateTracker()
    766                                         .isConcurrentVoiceAndDataAllowed())) {
    767                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
    768                         stopDataStallAlarm();
    769                         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
    770                     } else {
    771                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
    772                         stopDataStallAlarm();
    773                     }
    774                 }
    775 
    776                 break;
    777             }
    778             case DctConstants.EVENT_ICC_CHANGED: {
    779                 onUpdateIcc();
    780                 break;
    781             }
    782             default:
    783                 Rlog.e("DATA", "Unidentified event msg=" + msg);
    784                 break;
    785         }
    786     }
    787 
    788     /**
    789      * Report on whether data connectivity is enabled
    790      *
    791      * @return {@code false} if data connectivity has been explicitly disabled,
    792      *         {@code true} otherwise.
    793      */
    794     public boolean getAnyDataEnabled() {
    795         final boolean result;
    796         synchronized (mDataEnabledLock) {
    797             result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
    798                     && (mEnabledCount != 0));
    799         }
    800         if (!result && DBG) log("getAnyDataEnabled " + result);
    801         return result;
    802     }
    803 
    804     protected boolean isEmergency() {
    805         final boolean result;
    806         synchronized (mDataEnabledLock) {
    807             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
    808         }
    809         log("isEmergency: result=" + result);
    810         return result;
    811     }
    812 
    813     protected int apnTypeToId(String type) {
    814         if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DEFAULT)) {
    815             return DctConstants.APN_DEFAULT_ID;
    816         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_MMS)) {
    817             return DctConstants.APN_MMS_ID;
    818         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_SUPL)) {
    819             return DctConstants.APN_SUPL_ID;
    820         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DUN)) {
    821             return DctConstants.APN_DUN_ID;
    822         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_HIPRI)) {
    823             return DctConstants.APN_HIPRI_ID;
    824         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IMS)) {
    825             return DctConstants.APN_IMS_ID;
    826         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_FOTA)) {
    827             return DctConstants.APN_FOTA_ID;
    828         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_CBS)) {
    829             return DctConstants.APN_CBS_ID;
    830         } else {
    831             return DctConstants.APN_INVALID_ID;
    832         }
    833     }
    834 
    835     protected String apnIdToType(int id) {
    836         switch (id) {
    837         case DctConstants.APN_DEFAULT_ID:
    838             return PhoneConstants.APN_TYPE_DEFAULT;
    839         case DctConstants.APN_MMS_ID:
    840             return PhoneConstants.APN_TYPE_MMS;
    841         case DctConstants.APN_SUPL_ID:
    842             return PhoneConstants.APN_TYPE_SUPL;
    843         case DctConstants.APN_DUN_ID:
    844             return PhoneConstants.APN_TYPE_DUN;
    845         case DctConstants.APN_HIPRI_ID:
    846             return PhoneConstants.APN_TYPE_HIPRI;
    847         case DctConstants.APN_IMS_ID:
    848             return PhoneConstants.APN_TYPE_IMS;
    849         case DctConstants.APN_FOTA_ID:
    850             return PhoneConstants.APN_TYPE_FOTA;
    851         case DctConstants.APN_CBS_ID:
    852             return PhoneConstants.APN_TYPE_CBS;
    853         default:
    854             log("Unknown id (" + id + ") in apnIdToType");
    855             return PhoneConstants.APN_TYPE_DEFAULT;
    856         }
    857     }
    858 
    859     public LinkProperties getLinkProperties(String apnType) {
    860         int id = apnTypeToId(apnType);
    861 
    862         if (isApnIdEnabled(id)) {
    863             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
    864             return dcac.getLinkPropertiesSync();
    865         } else {
    866             return new LinkProperties();
    867         }
    868     }
    869 
    870     public LinkCapabilities getLinkCapabilities(String apnType) {
    871         int id = apnTypeToId(apnType);
    872         if (isApnIdEnabled(id)) {
    873             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
    874             return dcac.getLinkCapabilitiesSync();
    875         } else {
    876             return new LinkCapabilities();
    877         }
    878     }
    879 
    880     // tell all active apns of the current condition
    881     protected void notifyDataConnection(String reason) {
    882         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
    883             if (mDataEnabled[id]) {
    884                 mPhone.notifyDataConnection(reason, apnIdToType(id));
    885             }
    886         }
    887         notifyOffApnsOfAvailability(reason);
    888     }
    889 
    890     // a new APN has gone active and needs to send events to catch up with the
    891     // current condition
    892     private void notifyApnIdUpToCurrent(String reason, int apnId) {
    893         switch (mState) {
    894             case IDLE:
    895                 break;
    896             case RETRYING:
    897             case CONNECTING:
    898             case SCANNING:
    899                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
    900                         PhoneConstants.DataState.CONNECTING);
    901                 break;
    902             case CONNECTED:
    903             case DISCONNECTING:
    904                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
    905                         PhoneConstants.DataState.CONNECTING);
    906                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
    907                         PhoneConstants.DataState.CONNECTED);
    908                 break;
    909             default:
    910                 // Ignore
    911                 break;
    912         }
    913     }
    914 
    915     // since we normally don't send info to a disconnected APN, we need to do this specially
    916     private void notifyApnIdDisconnected(String reason, int apnId) {
    917         mPhone.notifyDataConnection(reason, apnIdToType(apnId),
    918                 PhoneConstants.DataState.DISCONNECTED);
    919     }
    920 
    921     // disabled apn's still need avail/unavail notificiations - send them out
    922     protected void notifyOffApnsOfAvailability(String reason) {
    923         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
    924         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
    925             if (!isApnIdEnabled(id)) {
    926                 notifyApnIdDisconnected(reason, id);
    927             }
    928         }
    929     }
    930 
    931     public boolean isApnTypeEnabled(String apnType) {
    932         if (apnType == null) {
    933             return false;
    934         } else {
    935             return isApnIdEnabled(apnTypeToId(apnType));
    936         }
    937     }
    938 
    939     protected synchronized boolean isApnIdEnabled(int id) {
    940         if (id != DctConstants.APN_INVALID_ID) {
    941             return mDataEnabled[id];
    942         }
    943         return false;
    944     }
    945 
    946     /**
    947      * Ensure that we are connected to an APN of the specified type.
    948      *
    949      * @param type the APN type (currently the only valid values are
    950      *            {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL})
    951      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
    952      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
    953      *         broadcast will be sent by the ConnectivityManager when a
    954      *         connection to the APN has been established.
    955      */
    956     public synchronized int enableApnType(String type) {
    957         int id = apnTypeToId(type);
    958         if (id == DctConstants.APN_INVALID_ID) {
    959             return PhoneConstants.APN_REQUEST_FAILED;
    960         }
    961 
    962         if (DBG) {
    963             log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
    964                     + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
    965         }
    966 
    967         if (!isApnTypeAvailable(type)) {
    968             if (DBG) log("type not available");
    969             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
    970         }
    971 
    972         if (isApnIdEnabled(id)) {
    973             return PhoneConstants.APN_ALREADY_ACTIVE;
    974         } else {
    975             setEnabled(id, true);
    976         }
    977         return PhoneConstants.APN_REQUEST_STARTED;
    978     }
    979 
    980     /**
    981      * The APN of the specified type is no longer needed. Ensure that if use of
    982      * the default APN has not been explicitly disabled, we are connected to the
    983      * default APN.
    984      *
    985      * @param type the APN type. The only valid values are currently
    986      *            {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL}.
    987      * @return Success is indicated by {@code PhoneConstants.APN_ALREADY_ACTIVE} or
    988      *         {@code PhoneConstants.APN_REQUEST_STARTED}. In the latter case, a
    989      *         broadcast will be sent by the ConnectivityManager when a
    990      *         connection to the APN has been disconnected. A {@code
    991      *         PhoneConstants.APN_REQUEST_FAILED} is returned if the type parameter is
    992      *         invalid or if the apn wasn't enabled.
    993      */
    994     public synchronized int disableApnType(String type) {
    995         if (DBG) log("disableApnType(" + type + ")");
    996         int id = apnTypeToId(type);
    997         if (id == DctConstants.APN_INVALID_ID) {
    998             return PhoneConstants.APN_REQUEST_FAILED;
    999         }
   1000         if (isApnIdEnabled(id)) {
   1001             setEnabled(id, false);
   1002             if (isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
   1003                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) {
   1004                     return PhoneConstants.APN_ALREADY_ACTIVE;
   1005                 } else {
   1006                     return PhoneConstants.APN_REQUEST_STARTED;
   1007                 }
   1008             } else {
   1009                 return PhoneConstants.APN_REQUEST_STARTED;
   1010             }
   1011         } else {
   1012             return PhoneConstants.APN_REQUEST_FAILED;
   1013         }
   1014     }
   1015 
   1016     protected void setEnabled(int id, boolean enable) {
   1017         if (DBG) {
   1018             log("setEnabled(" + id + ", " + enable + ") with old state = " + mDataEnabled[id]
   1019                     + " and enabledCount = " + mEnabledCount);
   1020         }
   1021         Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
   1022         msg.arg1 = id;
   1023         msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
   1024         sendMessage(msg);
   1025     }
   1026 
   1027     protected void onEnableApn(int apnId, int enabled) {
   1028         if (DBG) {
   1029             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
   1030                     ", enabled=" + enabled + ", dataEnabled = " + mDataEnabled[apnId] +
   1031                     ", enabledCount = " + mEnabledCount + ", isApnTypeActive = " +
   1032                     isApnTypeActive(apnIdToType(apnId)));
   1033         }
   1034         if (enabled == DctConstants.ENABLED) {
   1035             synchronized (this) {
   1036                 if (!mDataEnabled[apnId]) {
   1037                     mDataEnabled[apnId] = true;
   1038                     mEnabledCount++;
   1039                 }
   1040             }
   1041             String type = apnIdToType(apnId);
   1042             if (!isApnTypeActive(type)) {
   1043                 mRequestedApnType = type;
   1044                 onEnableNewApn();
   1045             } else {
   1046                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
   1047             }
   1048         } else {
   1049             // disable
   1050             boolean didDisable = false;
   1051             synchronized (this) {
   1052                 if (mDataEnabled[apnId]) {
   1053                     mDataEnabled[apnId] = false;
   1054                     mEnabledCount--;
   1055                     didDisable = true;
   1056                 }
   1057             }
   1058             if (didDisable) {
   1059                 if ((mEnabledCount == 0) || (apnId == DctConstants.APN_DUN_ID)) {
   1060                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
   1061                     onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
   1062                 }
   1063 
   1064                 // send the disconnect msg manually, since the normal route wont send
   1065                 // it (it's not enabled)
   1066                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
   1067                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID] == true
   1068                         && !isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
   1069                     // TODO - this is an ugly way to restore the default conn - should be done
   1070                     // by a real contention manager and policy that disconnects the lower pri
   1071                     // stuff as enable requests come in and pops them back on as we disable back
   1072                     // down to the lower pri stuff
   1073                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
   1074                     onEnableNewApn();
   1075                 }
   1076             }
   1077         }
   1078     }
   1079 
   1080     /**
   1081      * Called when we switch APNs.
   1082      *
   1083      * mRequestedApnType is set prior to call
   1084      * To be overridden.
   1085      */
   1086     protected void onEnableNewApn() {
   1087     }
   1088 
   1089     /**
   1090      * Called when EVENT_RESET_DONE is received so goto
   1091      * IDLE state and send notifications to those interested.
   1092      *
   1093      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
   1094      * TODO - needs to pass some notion of which connection is reset..
   1095      */
   1096     protected void onResetDone(AsyncResult ar) {
   1097         if (DBG) log("EVENT_RESET_DONE");
   1098         String reason = null;
   1099         if (ar.userObj instanceof String) {
   1100             reason = (String) ar.userObj;
   1101         }
   1102         gotoIdleAndNotifyDataConnection(reason);
   1103     }
   1104 
   1105     /**
   1106      * Prevent mobile data connections from being established, or once again
   1107      * allow mobile data connections. If the state toggles, then either tear
   1108      * down or set up data, as appropriate to match the new state.
   1109      *
   1110      * @param enable indicates whether to enable ({@code true}) or disable (
   1111      *            {@code false}) data
   1112      * @return {@code true} if the operation succeeded
   1113      */
   1114     public boolean setInternalDataEnabled(boolean enable) {
   1115         if (DBG)
   1116             log("setInternalDataEnabled(" + enable + ")");
   1117 
   1118         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE);
   1119         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
   1120         sendMessage(msg);
   1121         return true;
   1122     }
   1123 
   1124     protected void onSetInternalDataEnabled(boolean enabled) {
   1125         synchronized (mDataEnabledLock) {
   1126             mInternalDataEnabled = enabled;
   1127             if (enabled) {
   1128                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
   1129                 onTrySetupData(Phone.REASON_DATA_ENABLED);
   1130             } else {
   1131                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
   1132                 cleanUpAllConnections(null);
   1133             }
   1134         }
   1135     }
   1136 
   1137     public void cleanUpAllConnections(String cause) {
   1138         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
   1139         msg.obj = cause;
   1140         sendMessage(msg);
   1141     }
   1142 
   1143     public abstract boolean isDisconnected();
   1144 
   1145     protected void onSetUserDataEnabled(boolean enabled) {
   1146         synchronized (mDataEnabledLock) {
   1147             final boolean prevEnabled = getAnyDataEnabled();
   1148             if (mUserDataEnabled != enabled) {
   1149                 mUserDataEnabled = enabled;
   1150                 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
   1151                         Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
   1152                 if (getDataOnRoamingEnabled() == false &&
   1153                         mPhone.getServiceState().getRoaming() == true) {
   1154                     if (enabled) {
   1155                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
   1156                     } else {
   1157                         notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
   1158                     }
   1159                 }
   1160                 if (prevEnabled != getAnyDataEnabled()) {
   1161                     if (!prevEnabled) {
   1162                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1163                     } else {
   1164                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1165                     }
   1166                 }
   1167             }
   1168         }
   1169     }
   1170 
   1171     protected void onSetDependencyMet(String apnType, boolean met) {
   1172     }
   1173 
   1174     protected void onSetPolicyDataEnabled(boolean enabled) {
   1175         synchronized (mDataEnabledLock) {
   1176             final boolean prevEnabled = getAnyDataEnabled();
   1177             if (sPolicyDataEnabled != enabled) {
   1178                 sPolicyDataEnabled = enabled;
   1179                 if (prevEnabled != getAnyDataEnabled()) {
   1180                     if (!prevEnabled) {
   1181                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1182                     } else {
   1183                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1184                     }
   1185                 }
   1186             }
   1187         }
   1188     }
   1189 
   1190     protected String getReryConfig(boolean forDefault) {
   1191         int nt = mPhone.getServiceState().getNetworkType();
   1192 
   1193         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
   1194             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
   1195             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
   1196             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
   1197             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
   1198             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
   1199             // CDMA variant
   1200             return SystemProperties.get("ro.cdma.data_retry_config");
   1201         } else {
   1202             // Use GSM varient for all others.
   1203             if (forDefault) {
   1204                 return SystemProperties.get("ro.gsm.data_retry_config");
   1205             } else {
   1206                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
   1207             }
   1208         }
   1209     }
   1210 
   1211     protected void resetPollStats() {
   1212         mTxPkts = -1;
   1213         mRxPkts = -1;
   1214         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
   1215     }
   1216 
   1217     protected abstract DctConstants.State getOverallState();
   1218 
   1219     protected void startNetStatPoll() {
   1220         if (getOverallState() == DctConstants.State.CONNECTED
   1221                 && mNetStatPollEnabled == false) {
   1222             if (DBG) log("startNetStatPoll");
   1223             resetPollStats();
   1224             mNetStatPollEnabled = true;
   1225             mPollNetStat.run();
   1226         }
   1227     }
   1228 
   1229     protected void stopNetStatPoll() {
   1230         mNetStatPollEnabled = false;
   1231         removeCallbacks(mPollNetStat);
   1232         if (DBG) log("stopNetStatPoll");
   1233     }
   1234 
   1235     public void updateDataActivity() {
   1236         long sent, received;
   1237 
   1238         DctConstants.Activity newActivity;
   1239 
   1240         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
   1241         TxRxSum curTxRxSum = new TxRxSum();
   1242         curTxRxSum.updateTxRxSum();
   1243         mTxPkts = curTxRxSum.txPkts;
   1244         mRxPkts = curTxRxSum.rxPkts;
   1245 
   1246         if (VDBG) {
   1247             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
   1248         }
   1249 
   1250         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
   1251             sent = mTxPkts - preTxRxSum.txPkts;
   1252             received = mRxPkts - preTxRxSum.rxPkts;
   1253 
   1254             if (VDBG)
   1255                 log("updateDataActivity: sent=" + sent + " received=" + received);
   1256             if (sent > 0 && received > 0) {
   1257                 newActivity = DctConstants.Activity.DATAINANDOUT;
   1258             } else if (sent > 0 && received == 0) {
   1259                 newActivity = DctConstants.Activity.DATAOUT;
   1260             } else if (sent == 0 && received > 0) {
   1261                 newActivity = DctConstants.Activity.DATAIN;
   1262             } else {
   1263                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
   1264                         mActivity : DctConstants.Activity.NONE;
   1265             }
   1266 
   1267             if (mActivity != newActivity && mIsScreenOn) {
   1268                 if (VDBG)
   1269                     log("updateDataActivity: newActivity=" + newActivity);
   1270                 mActivity = newActivity;
   1271                 mPhone.notifyDataActivity();
   1272             }
   1273         }
   1274     }
   1275 
   1276     // Recovery action taken in case of data stall
   1277     protected static class RecoveryAction {
   1278         public static final int GET_DATA_CALL_LIST      = 0;
   1279         public static final int CLEANUP                 = 1;
   1280         public static final int REREGISTER              = 2;
   1281         public static final int RADIO_RESTART           = 3;
   1282         public static final int RADIO_RESTART_WITH_PROP = 4;
   1283 
   1284         private static boolean isAggressiveRecovery(int value) {
   1285             return ((value == RecoveryAction.CLEANUP) ||
   1286                     (value == RecoveryAction.REREGISTER) ||
   1287                     (value == RecoveryAction.RADIO_RESTART) ||
   1288                     (value == RecoveryAction.RADIO_RESTART_WITH_PROP));
   1289         }
   1290     }
   1291 
   1292     public int getRecoveryAction() {
   1293         int action = Settings.System.getInt(mPhone.getContext().getContentResolver(),
   1294                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
   1295         if (VDBG_STALL) log("getRecoveryAction: " + action);
   1296         return action;
   1297     }
   1298     public void putRecoveryAction(int action) {
   1299         Settings.System.putInt(mPhone.getContext().getContentResolver(),
   1300                 "radio.data.stall.recovery.action", action);
   1301         if (VDBG_STALL) log("putRecoveryAction: " + action);
   1302     }
   1303 
   1304     protected boolean isConnected() {
   1305         return false;
   1306     }
   1307 
   1308     protected void doRecovery() {
   1309         if (getOverallState() == DctConstants.State.CONNECTED) {
   1310             // Go through a series of recovery steps, each action transitions to the next action
   1311             int recoveryAction = getRecoveryAction();
   1312             switch (recoveryAction) {
   1313             case RecoveryAction.GET_DATA_CALL_LIST:
   1314                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
   1315                         mSentSinceLastRecv);
   1316                 if (DBG) log("doRecovery() get data call list");
   1317                 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
   1318                 putRecoveryAction(RecoveryAction.CLEANUP);
   1319                 break;
   1320             case RecoveryAction.CLEANUP:
   1321                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv);
   1322                 if (DBG) log("doRecovery() cleanup all connections");
   1323                 cleanUpAllConnections(Phone.REASON_PDP_RESET);
   1324                 putRecoveryAction(RecoveryAction.REREGISTER);
   1325                 break;
   1326             case RecoveryAction.REREGISTER:
   1327                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
   1328                         mSentSinceLastRecv);
   1329                 if (DBG) log("doRecovery() re-register");
   1330                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
   1331                 putRecoveryAction(RecoveryAction.RADIO_RESTART);
   1332                 break;
   1333             case RecoveryAction.RADIO_RESTART:
   1334                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
   1335                         mSentSinceLastRecv);
   1336                 if (DBG) log("restarting radio");
   1337                 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP);
   1338                 restartRadio();
   1339                 break;
   1340             case RecoveryAction.RADIO_RESTART_WITH_PROP:
   1341                 // This is in case radio restart has not recovered the data.
   1342                 // It will set an additional "gsm.radioreset" property to tell
   1343                 // RIL or system to take further action.
   1344                 // The implementation of hard reset recovery action is up to OEM product.
   1345                 // Once RADIO_RESET property is consumed, it is expected to set back
   1346                 // to false by RIL.
   1347                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1);
   1348                 if (DBG) log("restarting radio with gsm.radioreset to true");
   1349                 SystemProperties.set(RADIO_RESET_PROPERTY, "true");
   1350                 // give 1 sec so property change can be notified.
   1351                 try {
   1352                     Thread.sleep(1000);
   1353                 } catch (InterruptedException e) {}
   1354                 restartRadio();
   1355                 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1356                 break;
   1357             default:
   1358                 throw new RuntimeException("doRecovery: Invalid recoveryAction=" +
   1359                     recoveryAction);
   1360             }
   1361             mSentSinceLastRecv = 0;
   1362         }
   1363     }
   1364 
   1365     private void updateDataStallInfo() {
   1366         long sent, received;
   1367 
   1368         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
   1369         mDataStallTxRxSum.updateTxRxSum();
   1370 
   1371         if (VDBG_STALL) {
   1372             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
   1373                     " preTxRxSum=" + preTxRxSum);
   1374         }
   1375 
   1376         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
   1377         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
   1378 
   1379         if (RADIO_TESTS) {
   1380             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
   1381                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
   1382                 received = 0;
   1383             }
   1384         }
   1385         if ( sent > 0 && received > 0 ) {
   1386             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
   1387             mSentSinceLastRecv = 0;
   1388             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1389         } else if (sent > 0 && received == 0) {
   1390             if (mPhone.getState() == PhoneConstants.State.IDLE) {
   1391                 mSentSinceLastRecv += sent;
   1392             } else {
   1393                 mSentSinceLastRecv = 0;
   1394             }
   1395             if (DBG) {
   1396                 log("updateDataStallInfo: OUT sent=" + sent +
   1397                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
   1398             }
   1399         } else if (sent == 0 && received > 0) {
   1400             if (VDBG_STALL) log("updateDataStallInfo: IN");
   1401             mSentSinceLastRecv = 0;
   1402             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1403         } else {
   1404             if (VDBG_STALL) log("updateDataStallInfo: NONE");
   1405         }
   1406     }
   1407 
   1408     protected void onDataStallAlarm(int tag) {
   1409         if (mDataStallAlarmTag != tag) {
   1410             if (DBG) {
   1411                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
   1412             }
   1413             return;
   1414         }
   1415         updateDataStallInfo();
   1416 
   1417         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
   1418                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
   1419                 NUMBER_SENT_PACKETS_OF_HANG);
   1420 
   1421         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
   1422         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
   1423             if (DBG) {
   1424                 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
   1425             }
   1426             suspectedStall = DATA_STALL_SUSPECTED;
   1427             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
   1428         } else {
   1429             if (VDBG_STALL) {
   1430                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
   1431                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
   1432             }
   1433         }
   1434         startDataStallAlarm(suspectedStall);
   1435     }
   1436 
   1437     protected void startDataStallAlarm(boolean suspectedStall) {
   1438         int nextAction = getRecoveryAction();
   1439         int delayInMs;
   1440 
   1441         if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
   1442             // If screen is on or data stall is currently suspected, set the alarm
   1443             // with an aggresive timeout.
   1444             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
   1445                 delayInMs = Settings.Global.getInt(mResolver,
   1446                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
   1447                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
   1448             } else {
   1449                 delayInMs = Settings.Global.getInt(mResolver,
   1450                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
   1451                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
   1452             }
   1453 
   1454             mDataStallAlarmTag += 1;
   1455             if (VDBG_STALL) {
   1456                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
   1457                         " delay=" + (delayInMs / 1000) + "s");
   1458             }
   1459             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
   1460             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
   1461             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
   1462                     PendingIntent.FLAG_UPDATE_CURRENT);
   1463             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   1464                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
   1465         } else {
   1466             if (VDBG_STALL) {
   1467                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
   1468             }
   1469         }
   1470     }
   1471 
   1472     protected void stopDataStallAlarm() {
   1473         if (VDBG_STALL) {
   1474             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
   1475                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
   1476         }
   1477         mDataStallAlarmTag += 1;
   1478         if (mDataStallAlarmIntent != null) {
   1479             mAlarmManager.cancel(mDataStallAlarmIntent);
   1480             mDataStallAlarmIntent = null;
   1481         }
   1482     }
   1483 
   1484     protected void restartDataStallAlarm() {
   1485         if (isConnected() == false) return;
   1486         // To be called on screen status change.
   1487         // Do not cancel the alarm if it is set with aggressive timeout.
   1488         int nextAction = getRecoveryAction();
   1489 
   1490         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
   1491             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
   1492             return;
   1493         }
   1494         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
   1495         stopDataStallAlarm();
   1496         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
   1497     }
   1498 
   1499     void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
   1500         if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
   1501         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
   1502         msg.arg1 = tearDown ? 1 : 0;
   1503         msg.arg2 = 0;
   1504         msg.obj = apnContext;
   1505         sendMessage(msg);
   1506     }
   1507 
   1508     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1509         pw.println("DataConnectionTrackerBase:");
   1510         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
   1511         pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
   1512         pw.println(" mUserDataEnabled=" + mUserDataEnabled);
   1513         pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
   1514         pw.println(" mDataEnabled:");
   1515         for(int i=0; i < mDataEnabled.length; i++) {
   1516             pw.printf("  mDataEnabled[%d]=%b\n", i, mDataEnabled[i]);
   1517         }
   1518         pw.flush();
   1519         pw.println(" mEnabledCount=" + mEnabledCount);
   1520         pw.println(" mRequestedApnType=" + mRequestedApnType);
   1521         pw.println(" mPhone=" + mPhone.getPhoneName());
   1522         pw.println(" mActivity=" + mActivity);
   1523         pw.println(" mState=" + mState);
   1524         pw.println(" mTxPkts=" + mTxPkts);
   1525         pw.println(" mRxPkts=" + mRxPkts);
   1526         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
   1527         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
   1528         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
   1529         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
   1530         pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
   1531         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
   1532         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
   1533         pw.println(" mResolver=" + mResolver);
   1534         pw.println(" mIsWifiConnected=" + mIsWifiConnected);
   1535         pw.println(" mReconnectIntent=" + mReconnectIntent);
   1536         pw.println(" mCidActive=" + mCidActive);
   1537         pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
   1538         pw.println(" mIsScreenOn=" + mIsScreenOn);
   1539         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
   1540         pw.flush();
   1541         pw.println(" ***************************************");
   1542         DcController dcc = mDcc;
   1543         if (dcc != null) {
   1544             dcc.dump(fd, pw, args);
   1545         } else {
   1546             pw.println(" mDcc=null");
   1547         }
   1548         pw.println(" ***************************************");
   1549         HashMap<Integer, DataConnection> dcs = mDataConnections;
   1550         if (dcs != null) {
   1551             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
   1552             pw.println(" mDataConnections: count=" + mDcSet.size());
   1553             for (Entry<Integer, DataConnection> entry : mDcSet) {
   1554                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
   1555                 entry.getValue().dump(fd, pw, args);
   1556             }
   1557         } else {
   1558             pw.println("mDataConnections=null");
   1559         }
   1560         pw.println(" ***************************************");
   1561         pw.flush();
   1562         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
   1563         if (apnToDcId != null) {
   1564             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
   1565             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
   1566             for (Entry<String, Integer> entry : apnToDcIdSet) {
   1567                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
   1568             }
   1569         } else {
   1570             pw.println("mApnToDataConnectionId=null");
   1571         }
   1572         pw.println(" ***************************************");
   1573         pw.flush();
   1574         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
   1575         if (apnCtxs != null) {
   1576             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
   1577             pw.println(" mApnContexts size=" + apnCtxsSet.size());
   1578             for (Entry<String, ApnContext> entry : apnCtxsSet) {
   1579                 entry.getValue().dump(fd, pw, args);
   1580             }
   1581             pw.println(" ***************************************");
   1582         } else {
   1583             pw.println(" mApnContexts=null");
   1584         }
   1585         pw.flush();
   1586         pw.println(" mActiveApn=" + mActiveApn);
   1587         ArrayList<ApnSetting> apnSettings = mAllApnSettings;
   1588         if (apnSettings != null) {
   1589             pw.println(" mAllApnSettings size=" + apnSettings.size());
   1590             for (int i=0; i < apnSettings.size(); i++) {
   1591                 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
   1592             }
   1593             pw.flush();
   1594         } else {
   1595             pw.println(" mAllApnSettings=null");
   1596         }
   1597         pw.println(" mPreferredApn=" + mPreferredApn);
   1598         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
   1599         pw.println(" mIsDisposed=" + mIsDisposed);
   1600         pw.println(" mIntentReceiver=" + mIntentReceiver);
   1601         pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
   1602         pw.flush();
   1603     }
   1604 }
   1605