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                 Bundle bundle = msg.getData();
    853                 if (bundle != null) {
    854                     try {
    855                         mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY);
    856                     } catch(ClassCastException e) {
    857                         loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e);
    858                         mProvisioningUrl = null;
    859                     }
    860                 }
    861                 if (TextUtils.isEmpty(mProvisioningUrl)) {
    862                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring");
    863                     mIsProvisioning = false;
    864                     mProvisioningUrl = null;
    865                 } else {
    866                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl);
    867                     mIsProvisioning = true;
    868                     startProvisioningApnAlarm();
    869                     onSetInternalDataEnabled(true);
    870                     enableApnType("default");
    871                 }
    872                 break;
    873             }
    874             case DctConstants.EVENT_PROVISIONING_APN_ALARM: {
    875                 if (DBG) log("EVENT_PROVISIONING_APN_ALARM");
    876                 ApnContext apnCtx = mApnContexts.get("default");
    877                 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) {
    878                     if (mProvisioningApnAlarmTag == msg.arg1) {
    879                         if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting");
    880                         mIsProvisioning = false;
    881                         mProvisioningUrl = null;
    882                         stopProvisioningApnAlarm();
    883                         sendCleanUpConnection(true, apnCtx);
    884                     } else {
    885                         if (DBG) {
    886                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
    887                                     + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag
    888                                     + " != arg1:" + msg.arg1);
    889                         }
    890                     }
    891                 } else {
    892                     if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore");
    893                 }
    894                 break;
    895             }
    896             case DctConstants.CMD_IS_PROVISIONING_APN: {
    897                 if (DBG) log("CMD_IS_PROVISIONING_APN");
    898                 boolean isProvApn;
    899                 try {
    900                     String apnType = null;
    901                     Bundle bundle = msg.getData();
    902                     if (bundle != null) {
    903                         apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
    904                     }
    905                     if (TextUtils.isEmpty(apnType)) {
    906                         loge("CMD_IS_PROVISIONING_APN: apnType is empty");
    907                         isProvApn = false;
    908                     } else {
    909                         isProvApn = isProvisioningApn(apnType);
    910                     }
    911                 } catch (ClassCastException e) {
    912                     loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring");
    913                     isProvApn = false;
    914                 }
    915                 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn);
    916                 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN,
    917                         isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED);
    918                 break;
    919             }
    920             case DctConstants.EVENT_ICC_CHANGED: {
    921                 onUpdateIcc();
    922                 break;
    923             }
    924             case DctConstants.EVENT_RESTART_RADIO: {
    925                 restartRadio();
    926                 break;
    927             }
    928             default:
    929                 Rlog.e("DATA", "Unidentified event msg=" + msg);
    930                 break;
    931         }
    932     }
    933 
    934     /**
    935      * Report on whether data connectivity is enabled
    936      *
    937      * @return {@code false} if data connectivity has been explicitly disabled,
    938      *         {@code true} otherwise.
    939      */
    940     public boolean getAnyDataEnabled() {
    941         final boolean result;
    942         synchronized (mDataEnabledLock) {
    943             result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
    944                     && (mEnabledCount != 0));
    945         }
    946         if (!result && DBG) log("getAnyDataEnabled " + result);
    947         return result;
    948     }
    949 
    950     protected boolean isEmergency() {
    951         final boolean result;
    952         synchronized (mDataEnabledLock) {
    953             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
    954         }
    955         log("isEmergency: result=" + result);
    956         return result;
    957     }
    958 
    959     protected int apnTypeToId(String type) {
    960         if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DEFAULT)) {
    961             return DctConstants.APN_DEFAULT_ID;
    962         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_MMS)) {
    963             return DctConstants.APN_MMS_ID;
    964         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_SUPL)) {
    965             return DctConstants.APN_SUPL_ID;
    966         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DUN)) {
    967             return DctConstants.APN_DUN_ID;
    968         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_HIPRI)) {
    969             return DctConstants.APN_HIPRI_ID;
    970         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IMS)) {
    971             return DctConstants.APN_IMS_ID;
    972         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_FOTA)) {
    973             return DctConstants.APN_FOTA_ID;
    974         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_CBS)) {
    975             return DctConstants.APN_CBS_ID;
    976         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IA)) {
    977             return DctConstants.APN_IA_ID;
    978         } else {
    979             return DctConstants.APN_INVALID_ID;
    980         }
    981     }
    982 
    983     protected String apnIdToType(int id) {
    984         switch (id) {
    985         case DctConstants.APN_DEFAULT_ID:
    986             return PhoneConstants.APN_TYPE_DEFAULT;
    987         case DctConstants.APN_MMS_ID:
    988             return PhoneConstants.APN_TYPE_MMS;
    989         case DctConstants.APN_SUPL_ID:
    990             return PhoneConstants.APN_TYPE_SUPL;
    991         case DctConstants.APN_DUN_ID:
    992             return PhoneConstants.APN_TYPE_DUN;
    993         case DctConstants.APN_HIPRI_ID:
    994             return PhoneConstants.APN_TYPE_HIPRI;
    995         case DctConstants.APN_IMS_ID:
    996             return PhoneConstants.APN_TYPE_IMS;
    997         case DctConstants.APN_FOTA_ID:
    998             return PhoneConstants.APN_TYPE_FOTA;
    999         case DctConstants.APN_CBS_ID:
   1000             return PhoneConstants.APN_TYPE_CBS;
   1001         case DctConstants.APN_IA_ID:
   1002             return PhoneConstants.APN_TYPE_IA;
   1003         default:
   1004             log("Unknown id (" + id + ") in apnIdToType");
   1005             return PhoneConstants.APN_TYPE_DEFAULT;
   1006         }
   1007     }
   1008 
   1009     public LinkProperties getLinkProperties(String apnType) {
   1010         int id = apnTypeToId(apnType);
   1011 
   1012         if (isApnIdEnabled(id)) {
   1013             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
   1014             return dcac.getLinkPropertiesSync();
   1015         } else {
   1016             return new LinkProperties();
   1017         }
   1018     }
   1019 
   1020     public LinkCapabilities getLinkCapabilities(String apnType) {
   1021         int id = apnTypeToId(apnType);
   1022         if (isApnIdEnabled(id)) {
   1023             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
   1024             return dcac.getLinkCapabilitiesSync();
   1025         } else {
   1026             return new LinkCapabilities();
   1027         }
   1028     }
   1029 
   1030     // tell all active apns of the current condition
   1031     protected void notifyDataConnection(String reason) {
   1032         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
   1033             if (mDataEnabled[id]) {
   1034                 mPhone.notifyDataConnection(reason, apnIdToType(id));
   1035             }
   1036         }
   1037         notifyOffApnsOfAvailability(reason);
   1038     }
   1039 
   1040     // a new APN has gone active and needs to send events to catch up with the
   1041     // current condition
   1042     private void notifyApnIdUpToCurrent(String reason, int apnId) {
   1043         switch (mState) {
   1044             case IDLE:
   1045                 break;
   1046             case RETRYING:
   1047             case CONNECTING:
   1048             case SCANNING:
   1049                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
   1050                         PhoneConstants.DataState.CONNECTING);
   1051                 break;
   1052             case CONNECTED:
   1053             case DISCONNECTING:
   1054                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
   1055                         PhoneConstants.DataState.CONNECTING);
   1056                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
   1057                         PhoneConstants.DataState.CONNECTED);
   1058                 break;
   1059             default:
   1060                 // Ignore
   1061                 break;
   1062         }
   1063     }
   1064 
   1065     // since we normally don't send info to a disconnected APN, we need to do this specially
   1066     private void notifyApnIdDisconnected(String reason, int apnId) {
   1067         mPhone.notifyDataConnection(reason, apnIdToType(apnId),
   1068                 PhoneConstants.DataState.DISCONNECTED);
   1069     }
   1070 
   1071     // disabled apn's still need avail/unavail notificiations - send them out
   1072     protected void notifyOffApnsOfAvailability(String reason) {
   1073         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
   1074         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
   1075             if (!isApnIdEnabled(id)) {
   1076                 notifyApnIdDisconnected(reason, id);
   1077             }
   1078         }
   1079     }
   1080 
   1081     public boolean isApnTypeEnabled(String apnType) {
   1082         if (apnType == null) {
   1083             return false;
   1084         } else {
   1085             return isApnIdEnabled(apnTypeToId(apnType));
   1086         }
   1087     }
   1088 
   1089     protected synchronized boolean isApnIdEnabled(int id) {
   1090         if (id != DctConstants.APN_INVALID_ID) {
   1091             return mDataEnabled[id];
   1092         }
   1093         return false;
   1094     }
   1095 
   1096     /**
   1097      * Ensure that we are connected to an APN of the specified type.
   1098      *
   1099      * @param type the APN type (currently the only valid values are
   1100      *            {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL})
   1101      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
   1102      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
   1103      *         broadcast will be sent by the ConnectivityManager when a
   1104      *         connection to the APN has been established.
   1105      */
   1106     public synchronized int enableApnType(String type) {
   1107         int id = apnTypeToId(type);
   1108         if (id == DctConstants.APN_INVALID_ID) {
   1109             return PhoneConstants.APN_REQUEST_FAILED;
   1110         }
   1111 
   1112         if (DBG) {
   1113             log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
   1114                     + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
   1115         }
   1116 
   1117         if (!isApnTypeAvailable(type)) {
   1118             if (DBG) log("enableApnType: not available, type=" + type);
   1119             return PhoneConstants.APN_TYPE_NOT_AVAILABLE;
   1120         }
   1121 
   1122         if (isApnIdEnabled(id)) {
   1123             if (DBG) log("enableApnType: already active, type=" + type);
   1124             return PhoneConstants.APN_ALREADY_ACTIVE;
   1125         } else {
   1126             setEnabled(id, true);
   1127         }
   1128         return PhoneConstants.APN_REQUEST_STARTED;
   1129     }
   1130 
   1131     /**
   1132      * The APN of the specified type is no longer needed. Ensure that if use of
   1133      * the default APN has not been explicitly disabled, we are connected to the
   1134      * default APN.
   1135      *
   1136      * @param type the APN type. The only valid values are currently
   1137      *            {@link PhoneConstants#APN_TYPE_MMS} and {@link PhoneConstants#APN_TYPE_SUPL}.
   1138      * @return Success is indicated by {@code PhoneConstants.APN_ALREADY_ACTIVE} or
   1139      *         {@code PhoneConstants.APN_REQUEST_STARTED}. In the latter case, a
   1140      *         broadcast will be sent by the ConnectivityManager when a
   1141      *         connection to the APN has been disconnected. A {@code
   1142      *         PhoneConstants.APN_REQUEST_FAILED} is returned if the type parameter is
   1143      *         invalid or if the apn wasn't enabled.
   1144      */
   1145     public synchronized int disableApnType(String type) {
   1146         if (DBG) log("disableApnType(" + type + ")");
   1147         int id = apnTypeToId(type);
   1148         if (id == DctConstants.APN_INVALID_ID) {
   1149             return PhoneConstants.APN_REQUEST_FAILED;
   1150         }
   1151         if (isApnIdEnabled(id)) {
   1152             setEnabled(id, false);
   1153             if (isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
   1154                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) {
   1155                     return PhoneConstants.APN_ALREADY_ACTIVE;
   1156                 } else {
   1157                     return PhoneConstants.APN_REQUEST_STARTED;
   1158                 }
   1159             } else {
   1160                 return PhoneConstants.APN_REQUEST_STARTED;
   1161             }
   1162         } else {
   1163             return PhoneConstants.APN_REQUEST_FAILED;
   1164         }
   1165     }
   1166 
   1167     protected void setEnabled(int id, boolean enable) {
   1168         if (DBG) {
   1169             log("setEnabled(" + id + ", " + enable + ") with old state = " + mDataEnabled[id]
   1170                     + " and enabledCount = " + mEnabledCount);
   1171         }
   1172         Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
   1173         msg.arg1 = id;
   1174         msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
   1175         sendMessage(msg);
   1176     }
   1177 
   1178     protected void onEnableApn(int apnId, int enabled) {
   1179         if (DBG) {
   1180             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
   1181                     ", enabled=" + enabled + ", dataEnabled = " + mDataEnabled[apnId] +
   1182                     ", enabledCount = " + mEnabledCount + ", isApnTypeActive = " +
   1183                     isApnTypeActive(apnIdToType(apnId)));
   1184         }
   1185         if (enabled == DctConstants.ENABLED) {
   1186             synchronized (this) {
   1187                 if (!mDataEnabled[apnId]) {
   1188                     mDataEnabled[apnId] = true;
   1189                     mEnabledCount++;
   1190                 }
   1191             }
   1192             String type = apnIdToType(apnId);
   1193             if (!isApnTypeActive(type)) {
   1194                 mRequestedApnType = type;
   1195                 onEnableNewApn();
   1196             } else {
   1197                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
   1198             }
   1199         } else {
   1200             // disable
   1201             boolean didDisable = false;
   1202             synchronized (this) {
   1203                 if (mDataEnabled[apnId]) {
   1204                     mDataEnabled[apnId] = false;
   1205                     mEnabledCount--;
   1206                     didDisable = true;
   1207                 }
   1208             }
   1209             if (didDisable) {
   1210                 if ((mEnabledCount == 0) || (apnId == DctConstants.APN_DUN_ID)) {
   1211                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
   1212                     onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
   1213                 }
   1214 
   1215                 // send the disconnect msg manually, since the normal route wont send
   1216                 // it (it's not enabled)
   1217                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
   1218                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID] == true
   1219                         && !isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
   1220                     // TODO - this is an ugly way to restore the default conn - should be done
   1221                     // by a real contention manager and policy that disconnects the lower pri
   1222                     // stuff as enable requests come in and pops them back on as we disable back
   1223                     // down to the lower pri stuff
   1224                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
   1225                     onEnableNewApn();
   1226                 }
   1227             }
   1228         }
   1229     }
   1230 
   1231     /**
   1232      * Called when we switch APNs.
   1233      *
   1234      * mRequestedApnType is set prior to call
   1235      * To be overridden.
   1236      */
   1237     protected void onEnableNewApn() {
   1238     }
   1239 
   1240     /**
   1241      * Called when EVENT_RESET_DONE is received so goto
   1242      * IDLE state and send notifications to those interested.
   1243      *
   1244      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
   1245      * TODO - needs to pass some notion of which connection is reset..
   1246      */
   1247     protected void onResetDone(AsyncResult ar) {
   1248         if (DBG) log("EVENT_RESET_DONE");
   1249         String reason = null;
   1250         if (ar.userObj instanceof String) {
   1251             reason = (String) ar.userObj;
   1252         }
   1253         gotoIdleAndNotifyDataConnection(reason);
   1254     }
   1255 
   1256     /**
   1257      * Prevent mobile data connections from being established, or once again
   1258      * allow mobile data connections. If the state toggles, then either tear
   1259      * down or set up data, as appropriate to match the new state.
   1260      *
   1261      * @param enable indicates whether to enable ({@code true}) or disable (
   1262      *            {@code false}) data
   1263      * @return {@code true} if the operation succeeded
   1264      */
   1265     public boolean setInternalDataEnabled(boolean enable) {
   1266         if (DBG)
   1267             log("setInternalDataEnabled(" + enable + ")");
   1268 
   1269         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE);
   1270         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
   1271         sendMessage(msg);
   1272         return true;
   1273     }
   1274 
   1275     protected void onSetInternalDataEnabled(boolean enabled) {
   1276         synchronized (mDataEnabledLock) {
   1277             mInternalDataEnabled = enabled;
   1278             if (enabled) {
   1279                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
   1280                 onTrySetupData(Phone.REASON_DATA_ENABLED);
   1281             } else {
   1282                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
   1283                 cleanUpAllConnections(null);
   1284             }
   1285         }
   1286     }
   1287 
   1288     public void cleanUpAllConnections(String cause) {
   1289         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
   1290         msg.obj = cause;
   1291         sendMessage(msg);
   1292     }
   1293 
   1294     public abstract boolean isDisconnected();
   1295 
   1296     protected void onSetUserDataEnabled(boolean enabled) {
   1297         synchronized (mDataEnabledLock) {
   1298             final boolean prevEnabled = getAnyDataEnabled();
   1299             if (mUserDataEnabled != enabled) {
   1300                 mUserDataEnabled = enabled;
   1301                 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
   1302                         Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
   1303                 if (getDataOnRoamingEnabled() == false &&
   1304                         mPhone.getServiceState().getRoaming() == true) {
   1305                     if (enabled) {
   1306                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
   1307                     } else {
   1308                         notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
   1309                     }
   1310                 }
   1311                 if (prevEnabled != getAnyDataEnabled()) {
   1312                     if (!prevEnabled) {
   1313                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1314                     } else {
   1315                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1316                     }
   1317                 }
   1318             }
   1319         }
   1320     }
   1321 
   1322     protected void onSetDependencyMet(String apnType, boolean met) {
   1323     }
   1324 
   1325     protected void onSetPolicyDataEnabled(boolean enabled) {
   1326         synchronized (mDataEnabledLock) {
   1327             final boolean prevEnabled = getAnyDataEnabled();
   1328             if (sPolicyDataEnabled != enabled) {
   1329                 sPolicyDataEnabled = enabled;
   1330                 if (prevEnabled != getAnyDataEnabled()) {
   1331                     if (!prevEnabled) {
   1332                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1333                     } else {
   1334                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1335                     }
   1336                 }
   1337             }
   1338         }
   1339     }
   1340 
   1341     protected String getReryConfig(boolean forDefault) {
   1342         int nt = mPhone.getServiceState().getNetworkType();
   1343 
   1344         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
   1345             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
   1346             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
   1347             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
   1348             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
   1349             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
   1350             // CDMA variant
   1351             return SystemProperties.get("ro.cdma.data_retry_config");
   1352         } else {
   1353             // Use GSM varient for all others.
   1354             if (forDefault) {
   1355                 return SystemProperties.get("ro.gsm.data_retry_config");
   1356             } else {
   1357                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
   1358             }
   1359         }
   1360     }
   1361 
   1362     protected void resetPollStats() {
   1363         mTxPkts = -1;
   1364         mRxPkts = -1;
   1365         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
   1366     }
   1367 
   1368     protected abstract DctConstants.State getOverallState();
   1369 
   1370     protected void startNetStatPoll() {
   1371         if (getOverallState() == DctConstants.State.CONNECTED
   1372                 && mNetStatPollEnabled == false) {
   1373             if (DBG) log("startNetStatPoll");
   1374             resetPollStats();
   1375             mNetStatPollEnabled = true;
   1376             mPollNetStat.run();
   1377         }
   1378     }
   1379 
   1380     protected void stopNetStatPoll() {
   1381         mNetStatPollEnabled = false;
   1382         removeCallbacks(mPollNetStat);
   1383         if (DBG) log("stopNetStatPoll");
   1384     }
   1385 
   1386     public void updateDataActivity() {
   1387         long sent, received;
   1388 
   1389         DctConstants.Activity newActivity;
   1390 
   1391         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
   1392         TxRxSum curTxRxSum = new TxRxSum();
   1393         curTxRxSum.updateTxRxSum();
   1394         mTxPkts = curTxRxSum.txPkts;
   1395         mRxPkts = curTxRxSum.rxPkts;
   1396 
   1397         if (VDBG) {
   1398             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
   1399         }
   1400 
   1401         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
   1402             sent = mTxPkts - preTxRxSum.txPkts;
   1403             received = mRxPkts - preTxRxSum.rxPkts;
   1404 
   1405             if (VDBG)
   1406                 log("updateDataActivity: sent=" + sent + " received=" + received);
   1407             if (sent > 0 && received > 0) {
   1408                 newActivity = DctConstants.Activity.DATAINANDOUT;
   1409             } else if (sent > 0 && received == 0) {
   1410                 newActivity = DctConstants.Activity.DATAOUT;
   1411             } else if (sent == 0 && received > 0) {
   1412                 newActivity = DctConstants.Activity.DATAIN;
   1413             } else {
   1414                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
   1415                         mActivity : DctConstants.Activity.NONE;
   1416             }
   1417 
   1418             if (mActivity != newActivity && mIsScreenOn) {
   1419                 if (VDBG)
   1420                     log("updateDataActivity: newActivity=" + newActivity);
   1421                 mActivity = newActivity;
   1422                 mPhone.notifyDataActivity();
   1423             }
   1424         }
   1425     }
   1426 
   1427     // Recovery action taken in case of data stall
   1428     protected static class RecoveryAction {
   1429         public static final int GET_DATA_CALL_LIST      = 0;
   1430         public static final int CLEANUP                 = 1;
   1431         public static final int REREGISTER              = 2;
   1432         public static final int RADIO_RESTART           = 3;
   1433         public static final int RADIO_RESTART_WITH_PROP = 4;
   1434 
   1435         private static boolean isAggressiveRecovery(int value) {
   1436             return ((value == RecoveryAction.CLEANUP) ||
   1437                     (value == RecoveryAction.REREGISTER) ||
   1438                     (value == RecoveryAction.RADIO_RESTART) ||
   1439                     (value == RecoveryAction.RADIO_RESTART_WITH_PROP));
   1440         }
   1441     }
   1442 
   1443     public int getRecoveryAction() {
   1444         int action = Settings.System.getInt(mPhone.getContext().getContentResolver(),
   1445                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
   1446         if (VDBG_STALL) log("getRecoveryAction: " + action);
   1447         return action;
   1448     }
   1449     public void putRecoveryAction(int action) {
   1450         Settings.System.putInt(mPhone.getContext().getContentResolver(),
   1451                 "radio.data.stall.recovery.action", action);
   1452         if (VDBG_STALL) log("putRecoveryAction: " + action);
   1453     }
   1454 
   1455     protected boolean isConnected() {
   1456         return false;
   1457     }
   1458 
   1459     protected void doRecovery() {
   1460         if (getOverallState() == DctConstants.State.CONNECTED) {
   1461             // Go through a series of recovery steps, each action transitions to the next action
   1462             int recoveryAction = getRecoveryAction();
   1463             switch (recoveryAction) {
   1464             case RecoveryAction.GET_DATA_CALL_LIST:
   1465                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
   1466                         mSentSinceLastRecv);
   1467                 if (DBG) log("doRecovery() get data call list");
   1468                 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
   1469                 putRecoveryAction(RecoveryAction.CLEANUP);
   1470                 break;
   1471             case RecoveryAction.CLEANUP:
   1472                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv);
   1473                 if (DBG) log("doRecovery() cleanup all connections");
   1474                 cleanUpAllConnections(Phone.REASON_PDP_RESET);
   1475                 putRecoveryAction(RecoveryAction.REREGISTER);
   1476                 break;
   1477             case RecoveryAction.REREGISTER:
   1478                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
   1479                         mSentSinceLastRecv);
   1480                 if (DBG) log("doRecovery() re-register");
   1481                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
   1482                 putRecoveryAction(RecoveryAction.RADIO_RESTART);
   1483                 break;
   1484             case RecoveryAction.RADIO_RESTART:
   1485                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
   1486                         mSentSinceLastRecv);
   1487                 if (DBG) log("restarting radio");
   1488                 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP);
   1489                 restartRadio();
   1490                 break;
   1491             case RecoveryAction.RADIO_RESTART_WITH_PROP:
   1492                 // This is in case radio restart has not recovered the data.
   1493                 // It will set an additional "gsm.radioreset" property to tell
   1494                 // RIL or system to take further action.
   1495                 // The implementation of hard reset recovery action is up to OEM product.
   1496                 // Once RADIO_RESET property is consumed, it is expected to set back
   1497                 // to false by RIL.
   1498                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1);
   1499                 if (DBG) log("restarting radio with gsm.radioreset to true");
   1500                 SystemProperties.set(RADIO_RESET_PROPERTY, "true");
   1501                 // give 1 sec so property change can be notified.
   1502                 try {
   1503                     Thread.sleep(1000);
   1504                 } catch (InterruptedException e) {}
   1505                 restartRadio();
   1506                 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1507                 break;
   1508             default:
   1509                 throw new RuntimeException("doRecovery: Invalid recoveryAction=" +
   1510                     recoveryAction);
   1511             }
   1512             mSentSinceLastRecv = 0;
   1513         }
   1514     }
   1515 
   1516     private void updateDataStallInfo() {
   1517         long sent, received;
   1518 
   1519         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
   1520         mDataStallTxRxSum.updateTxRxSum();
   1521 
   1522         if (VDBG_STALL) {
   1523             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
   1524                     " preTxRxSum=" + preTxRxSum);
   1525         }
   1526 
   1527         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
   1528         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
   1529 
   1530         if (RADIO_TESTS) {
   1531             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
   1532                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
   1533                 received = 0;
   1534             }
   1535         }
   1536         if ( sent > 0 && received > 0 ) {
   1537             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
   1538             mSentSinceLastRecv = 0;
   1539             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1540         } else if (sent > 0 && received == 0) {
   1541             if (mPhone.getState() == PhoneConstants.State.IDLE) {
   1542                 mSentSinceLastRecv += sent;
   1543             } else {
   1544                 mSentSinceLastRecv = 0;
   1545             }
   1546             if (DBG) {
   1547                 log("updateDataStallInfo: OUT sent=" + sent +
   1548                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
   1549             }
   1550         } else if (sent == 0 && received > 0) {
   1551             if (VDBG_STALL) log("updateDataStallInfo: IN");
   1552             mSentSinceLastRecv = 0;
   1553             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
   1554         } else {
   1555             if (VDBG_STALL) log("updateDataStallInfo: NONE");
   1556         }
   1557     }
   1558 
   1559     protected void onDataStallAlarm(int tag) {
   1560         if (mDataStallAlarmTag != tag) {
   1561             if (DBG) {
   1562                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
   1563             }
   1564             return;
   1565         }
   1566         updateDataStallInfo();
   1567 
   1568         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
   1569                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
   1570                 NUMBER_SENT_PACKETS_OF_HANG);
   1571 
   1572         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
   1573         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
   1574             if (DBG) {
   1575                 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
   1576             }
   1577             suspectedStall = DATA_STALL_SUSPECTED;
   1578             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
   1579         } else {
   1580             if (VDBG_STALL) {
   1581                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
   1582                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
   1583             }
   1584         }
   1585         startDataStallAlarm(suspectedStall);
   1586     }
   1587 
   1588     protected void startDataStallAlarm(boolean suspectedStall) {
   1589         int nextAction = getRecoveryAction();
   1590         int delayInMs;
   1591 
   1592         if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
   1593             // If screen is on or data stall is currently suspected, set the alarm
   1594             // with an aggresive timeout.
   1595             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
   1596                 delayInMs = Settings.Global.getInt(mResolver,
   1597                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
   1598                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
   1599             } else {
   1600                 delayInMs = Settings.Global.getInt(mResolver,
   1601                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
   1602                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
   1603             }
   1604 
   1605             mDataStallAlarmTag += 1;
   1606             if (VDBG_STALL) {
   1607                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
   1608                         " delay=" + (delayInMs / 1000) + "s");
   1609             }
   1610             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
   1611             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
   1612             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
   1613                     PendingIntent.FLAG_UPDATE_CURRENT);
   1614             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   1615                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
   1616         } else {
   1617             if (VDBG_STALL) {
   1618                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
   1619             }
   1620         }
   1621     }
   1622 
   1623     protected void stopDataStallAlarm() {
   1624         if (VDBG_STALL) {
   1625             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
   1626                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
   1627         }
   1628         mDataStallAlarmTag += 1;
   1629         if (mDataStallAlarmIntent != null) {
   1630             mAlarmManager.cancel(mDataStallAlarmIntent);
   1631             mDataStallAlarmIntent = null;
   1632         }
   1633     }
   1634 
   1635     protected void restartDataStallAlarm() {
   1636         if (isConnected() == false) return;
   1637         // To be called on screen status change.
   1638         // Do not cancel the alarm if it is set with aggressive timeout.
   1639         int nextAction = getRecoveryAction();
   1640 
   1641         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
   1642             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
   1643             return;
   1644         }
   1645         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
   1646         stopDataStallAlarm();
   1647         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
   1648     }
   1649 
   1650     protected void setInitialAttachApn() {
   1651         ApnSetting iaApnSetting = null;
   1652         ApnSetting defaultApnSetting = null;
   1653         ApnSetting firstApnSetting = null;
   1654 
   1655         log("setInitialApn: E mPreferredApn=" + mPreferredApn);
   1656 
   1657         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
   1658             firstApnSetting = mAllApnSettings.get(0);
   1659             log("setInitialApn: firstApnSetting=" + firstApnSetting);
   1660 
   1661             // Search for Initial APN setting and the first apn that can handle default
   1662             for (ApnSetting apn : mAllApnSettings) {
   1663                 // Can't use apn.canHandleType(), as that returns true for APNs that have no type.
   1664                 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA)) {
   1665                     // The Initial Attach APN is highest priority so use it if there is one
   1666                     log("setInitialApn: iaApnSetting=" + apn);
   1667                     iaApnSetting = apn;
   1668                     break;
   1669                 } else if ((defaultApnSetting == null)
   1670                         && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) {
   1671                     // Use the first default apn if no better choice
   1672                     log("setInitialApn: defaultApnSetting=" + apn);
   1673                     defaultApnSetting = apn;
   1674                 }
   1675             }
   1676         }
   1677 
   1678         // The priority of apn candidates from highest to lowest is:
   1679         //   1) APN_TYPE_IA (Inital Attach)
   1680         //   2) mPreferredApn, i.e. the current preferred apn
   1681         //   3) The first apn that than handle APN_TYPE_DEFAULT
   1682         //   4) The first APN we can find.
   1683 
   1684         ApnSetting initialAttachApnSetting = null;
   1685         if (iaApnSetting != null) {
   1686             if (DBG) log("setInitialAttachApn: using iaApnSetting");
   1687             initialAttachApnSetting = iaApnSetting;
   1688         } else if (mPreferredApn != null) {
   1689             if (DBG) log("setInitialAttachApn: using mPreferredApn");
   1690             initialAttachApnSetting = mPreferredApn;
   1691         } else if (defaultApnSetting != null) {
   1692             if (DBG) log("setInitialAttachApn: using defaultApnSetting");
   1693             initialAttachApnSetting = defaultApnSetting;
   1694         } else if (firstApnSetting != null) {
   1695             if (DBG) log("setInitialAttachApn: using firstApnSetting");
   1696             initialAttachApnSetting = firstApnSetting;
   1697         }
   1698 
   1699         if (initialAttachApnSetting == null) {
   1700             if (DBG) log("setInitialAttachApn: X There in no available apn");
   1701         } else {
   1702             if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting);
   1703 
   1704             mPhone.mCi.setInitialAttachApn(initialAttachApnSetting.apn,
   1705                     initialAttachApnSetting.protocol, initialAttachApnSetting.authType,
   1706                     initialAttachApnSetting.user, initialAttachApnSetting.password, null);
   1707         }
   1708     }
   1709 
   1710     protected void onActionIntentProvisioningApnAlarm(Intent intent) {
   1711         if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction());
   1712         Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM,
   1713                 intent.getAction());
   1714         msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0);
   1715         sendMessage(msg);
   1716     }
   1717 
   1718     protected void startProvisioningApnAlarm() {
   1719         int delayInMs = Settings.Global.getInt(mResolver,
   1720                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
   1721                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
   1722         if (Build.IS_DEBUGGABLE) {
   1723             // Allow debug code to use a system property to provide another value
   1724             String delayInMsStrg = Integer.toString(delayInMs);
   1725             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
   1726             try {
   1727                 delayInMs = Integer.parseInt(delayInMsStrg);
   1728             } catch (NumberFormatException e) {
   1729                 loge("startProvisioningApnAlarm: e=" + e);
   1730             }
   1731         }
   1732         mProvisioningApnAlarmTag += 1;
   1733         if (DBG) {
   1734             log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag +
   1735                     " delay=" + (delayInMs / 1000) + "s");
   1736         }
   1737         Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM);
   1738         intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag);
   1739         mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
   1740                 PendingIntent.FLAG_UPDATE_CURRENT);
   1741         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   1742                 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent);
   1743     }
   1744 
   1745     protected void stopProvisioningApnAlarm() {
   1746         if (DBG) {
   1747             log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag +
   1748                     " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent);
   1749         }
   1750         mProvisioningApnAlarmTag += 1;
   1751         if (mProvisioningApnAlarmIntent != null) {
   1752             mAlarmManager.cancel(mProvisioningApnAlarmIntent);
   1753             mProvisioningApnAlarmIntent = null;
   1754         }
   1755     }
   1756 
   1757     void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
   1758         if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
   1759         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
   1760         msg.arg1 = tearDown ? 1 : 0;
   1761         msg.arg2 = 0;
   1762         msg.obj = apnContext;
   1763         sendMessage(msg);
   1764     }
   1765 
   1766     void sendRestartRadio() {
   1767         if (DBG)log("sendRestartRadio:");
   1768         Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO);
   1769         sendMessage(msg);
   1770     }
   1771 
   1772     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1773         pw.println("DataConnectionTrackerBase:");
   1774         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
   1775         pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
   1776         pw.println(" mUserDataEnabled=" + mUserDataEnabled);
   1777         pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
   1778         pw.println(" mDataEnabled:");
   1779         for(int i=0; i < mDataEnabled.length; i++) {
   1780             pw.printf("  mDataEnabled[%d]=%b\n", i, mDataEnabled[i]);
   1781         }
   1782         pw.flush();
   1783         pw.println(" mEnabledCount=" + mEnabledCount);
   1784         pw.println(" mRequestedApnType=" + mRequestedApnType);
   1785         pw.println(" mPhone=" + mPhone.getPhoneName());
   1786         pw.println(" mActivity=" + mActivity);
   1787         pw.println(" mState=" + mState);
   1788         pw.println(" mTxPkts=" + mTxPkts);
   1789         pw.println(" mRxPkts=" + mRxPkts);
   1790         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
   1791         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
   1792         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
   1793         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
   1794         pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
   1795         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
   1796         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
   1797         pw.println(" mResolver=" + mResolver);
   1798         pw.println(" mIsWifiConnected=" + mIsWifiConnected);
   1799         pw.println(" mReconnectIntent=" + mReconnectIntent);
   1800         pw.println(" mCidActive=" + mCidActive);
   1801         pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
   1802         pw.println(" mIsScreenOn=" + mIsScreenOn);
   1803         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
   1804         pw.flush();
   1805         pw.println(" ***************************************");
   1806         DcController dcc = mDcc;
   1807         if (dcc != null) {
   1808             dcc.dump(fd, pw, args);
   1809         } else {
   1810             pw.println(" mDcc=null");
   1811         }
   1812         pw.println(" ***************************************");
   1813         HashMap<Integer, DataConnection> dcs = mDataConnections;
   1814         if (dcs != null) {
   1815             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
   1816             pw.println(" mDataConnections: count=" + mDcSet.size());
   1817             for (Entry<Integer, DataConnection> entry : mDcSet) {
   1818                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
   1819                 entry.getValue().dump(fd, pw, args);
   1820             }
   1821         } else {
   1822             pw.println("mDataConnections=null");
   1823         }
   1824         pw.println(" ***************************************");
   1825         pw.flush();
   1826         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
   1827         if (apnToDcId != null) {
   1828             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
   1829             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
   1830             for (Entry<String, Integer> entry : apnToDcIdSet) {
   1831                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
   1832             }
   1833         } else {
   1834             pw.println("mApnToDataConnectionId=null");
   1835         }
   1836         pw.println(" ***************************************");
   1837         pw.flush();
   1838         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
   1839         if (apnCtxs != null) {
   1840             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
   1841             pw.println(" mApnContexts size=" + apnCtxsSet.size());
   1842             for (Entry<String, ApnContext> entry : apnCtxsSet) {
   1843                 entry.getValue().dump(fd, pw, args);
   1844             }
   1845             pw.println(" ***************************************");
   1846         } else {
   1847             pw.println(" mApnContexts=null");
   1848         }
   1849         pw.flush();
   1850         pw.println(" mActiveApn=" + mActiveApn);
   1851         ArrayList<ApnSetting> apnSettings = mAllApnSettings;
   1852         if (apnSettings != null) {
   1853             pw.println(" mAllApnSettings size=" + apnSettings.size());
   1854             for (int i=0; i < apnSettings.size(); i++) {
   1855                 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
   1856             }
   1857             pw.flush();
   1858         } else {
   1859             pw.println(" mAllApnSettings=null");
   1860         }
   1861         pw.println(" mPreferredApn=" + mPreferredApn);
   1862         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
   1863         pw.println(" mIsDisposed=" + mIsDisposed);
   1864         pw.println(" mIntentReceiver=" + mIntentReceiver);
   1865         pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
   1866         pw.flush();
   1867     }
   1868 }
   1869