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