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